1 INTRODUCTION

nhanes <- read.csv("https://jmusa3.github.io/jmusa/nhanes.csv")

#CREATE MISSING VALUES in some variables

# Set seed for reproducibility
set.seed(123)  

# Determine the number of missing values (15% of total rows)
num_missing <- round(0.14 * nrow(nhanes))

# Randomly select row indices to introduce missing values 
missing_indices <- sample(1:nrow(nhanes), num_missing, replace = FALSE)

# Set selected rows in body.weight to NA
nhanes$body.weight[missing_indices] <- NA

# Verify missing values
#sum(is.na(nhanes$body.weight))  


# Set seed for reproducibility
set.seed(456)  

# Determine the number of missing values (15% of total rows)
num_missing <- round(0.15 * nrow(nhanes))

# Randomly select row indices to introduce missing values
missing_indices <- sample(1:nrow(nhanes), num_missing, replace = FALSE)

# Set selected rows in body.weight to NA
nhanes$cholestrol[missing_indices] <- NA


# Set seed for reproducibility
set.seed(789)  

# Determine the number of missing values (15% of total rows)
num_missing <- round(0.15 * nrow(nhanes))

# Randomly select row indices to introduce missing values
missing_indices <- sample(1:nrow(nhanes), num_missing, replace = FALSE)

# Set selected rows in race to NA
nhanes$race[missing_indices] <- NA

# Verify missing values

#sum(is.na(nhanes$race))  
#sum(is.na(nhanes$cholestrol)) 
#sum(is.na(nhanes$body.weight)) 

# create a copy of nhanes for MICE
nhanes1 <- nhanes
nhanes1$race <- as.factor(nhanes1$race)
nhanes1$cholestrol <- as.numeric(nhanes1$cholestrol)

The National Health and Nutrition Examination Survey (NHANES) is a program conducted by the National Center for Health Statistics (NCHS), a division of the Centers for Disease Control and Prevention (CDC). NHANES has been conducted in various forms since the early 1960s, with the current continuous survey format beginning in 1999. The survey is designed to assess the health and nutritional status of adults and children in the United States through a combination of interviews, physical examinations, and laboratory tests. Data is collected from a nationally representative sample of the U.S. population using a complex, multistage probability sampling design. Participants undergo household interviews followed by health examinations at mobile examination centers (MECs), where trained medical professionals collect biological samples and conduct clinical assessments. The NHANES data provides critical insights into public health trends, helping policymakers, researchers, and healthcare professionals make informed decisions on national health priorities. The purpose of this study is to assess the health and nutritional status of the study participants with metrics such as high blood pressure.

There are 15 features and 7927 observations in this data set. These features are listed below.

  1. obs: Respondent Identification Number
  2. psu: Pseudo-PSU 1,2 psu
  3. stratum: Pseudo-stratum (01 - 49)
  4. stat.weight: Statistical weight (225.93 - 139744.9)
  5. age: Age (years)
  6. sex: 0 = Female, 1 = Male sex
  7. race: Race (1 = White; 2 = Black; 3 = Other)
  8. body.weight: Body Weight (pounds)
  9. height: Standing Height (inches)
  10. avg.sbp: Average Systolic BP (mm/Hg)
  11. avg.dbp: Average Diastolic BP (mm/Hg)
  12. past.smk: Has respondent smoked > 100 cigarettes in life (1 = Yes, 2 = No)
  13. current.smk: Does respondent smoke cigarettes now? (1 = Yes, 2 = No)
  14. cholestrol: Serum Cholesterol (mg/100ml)
  15. hbp: High Blood Pressure (0 if PEPMNK1R <= 140; 1 if PEPMNK1R > 140)

The obs, psu, stratum, and stat.weight variables are not included in this analysis because they do not directly provide health-related information.

The data set has 317 missing values for body weight and 396 missing values for cholesterol.

2 EDA

2.1 Distribution of Individual Features

The distributions of the individual features in the NHANES dataset provide a snapshot of the characteristics of the population in terms of various health and demographic variables. Understanding these distributions is essential for identifying patterns, detecting potential biases, and assessing the range and variability of each feature. This analysis helps in understanding how variables such as age, body weight, blood pressure, and lifestyle factors are spread across the dataset, which is crucial for subsequent statistical modeling and interpretation.

# Convert variables to factors with proper labels
nhanes$sex <- factor(nhanes$sex, levels = c(0, 1), labels = c("Female", "Male"))
nhanes$race <- factor(nhanes$race, levels = c(1, 2, 3), labels = c("White", "Black", "Other"))
nhanes$past.smk <- factor(nhanes$past.smk, levels = c(1, 2), labels = c("Yes", "No"))
nhanes$current.smk <- factor(nhanes$current.smk, levels = c(1, 2), labels = c("Yes", "No"))

# Create frequency tables
sex_count <- table(nhanes$sex)

race_count <- table(nhanes$race)

past.smk_count <- table(nhanes$past.smk)

current.smk_count <- table(nhanes$current.smk)


par(mfrow = c(2, 2))

# Plot the bar charts
barplot(height = sex_count, col = "steelblue", main = "Sex", xlab = "Sex", ylab = "Count")

barplot(height = race_count, col = "steelblue", main = "Race", xlab = "Race", ylab = "Count")

barplot(height = past.smk_count, col = "steelblue", main = "Past Smoker", xlab = "Past Smoker", ylab = "Count")

barplot(height = current.smk_count, col = "steelblue", main = "Current Smoker", xlab = "Current Smoker", ylab = "Count")

There are slightly more male observations than female observation in this data set. The majority of participants are white, followed by black. All participants are recorded as being past smokers, which is likely an error. There is an imbalance for past smoker. In turn, past smoker cannot be used for analysis. About half of current participants are current smokers.

par(mfrow = c(2, 2))  

# Histogram for Cholesterol
hist(nhanes$cholestrol, 
     main = "Histogram of Cholesterol", 
     xlab = "Cholesterol", 
     col = "steelblue", 
     border = "black", 
     breaks = 20)  # Control number of bins
    
     
# Histogram for Systolic BP
hist(nhanes$avg.sbp, 
     main = "Histogram of Systolic BP", 
     xlab = "Systolic BP", 
     col = "steelblue", 
     border = "black", 
     breaks = 20)
    

# Histogram for Body Weight
hist(nhanes$body.weight, 
     main = "Histogram of Body Weight", 
     xlab = "Body Weight", 
     col = "steelblue", 
     border = "black", 
     breaks = 20)
  
     
# Histogram for Height
hist(nhanes$body.weight, 
     main = "Histogram of Height", 
     xlab = "Height", 
     col = "steelblue", 
     border = "black", 
     breaks = 20)   

Most participants do not have high blood pressure. The age of participants varies from about 20 to about 90. The height distribution is roughly symmetric. The body weight distribution is skewed right due to some high outliers. The high outliers may indicate obesity.

par(mfrow = c(2,2))

hist(nhanes$avg.sbp, col = "steelblue", 
     main = "Systolic BP",
     xlab = "Systolic BP", ylab = "Frequency",
     breaks = 30)

hist(nhanes$avg.dbp, col = "steelblue", 
     main = "Diastolic BP",
     xlab = "Diastolic BP", ylab = "Frequency",
     breaks = 30)

hist(nhanes$cholestrol, col = "steelblue", 
     main = "Cholesterol",
     xlab = "Cholesterol", ylab = "Frequency",
     breaks = 30)

Systolic BP and cholesterol have skewed right distributions. Diastolic BP is roughly symmetric. Of the 7927 participants, 1964 are obese.

2.2 Relationship between Features

Examining relationships between variables using scatterplots and a correlation matrix provides a comprehensive approach to understanding associations. Scatterplots visually reveal how two continuous variables interact, allowing us to identify trends, correlations, and potential outliers. Meanwhile, a correlation matrix quantifies the strength and direction of relationships between multiple variables at once, helping to pinpoint which pairs are strongly correlated. Together, scatterplots and a correlation matrix offer valuable insights into the underlying patterns in the data, guiding further statistical analysis and model selection.

# Set seed for reproducibility
set.seed(123)

# Sample 500 rows (adjust the number as needed)
sample_indices <- sample(nrow(nhanes), size = 500, replace = TRUE)
sampled_data <- nhanes[sample_indices, c("age", "body.weight", "height", "avg.sbp", "avg.dbp", "cholestrol")]

# Create a pairwise scatterplot matrix with the sampled data
pairs(sampled_data, 
      main = "Pairwise Scatterplots (Bootstrapped Sample)",
      pch = 19,           # Shape of the points (circle)
      col = rgb(0, 0, 1, 0.5)  # Color with transparency (blue)
)

nhanes_subset <- nhanes[, c("age", "body.weight", "height", "avg.sbp", "avg.dbp", "cholestrol")]

# Compute the correlation matrix
cor_matrix <- cor(nhanes_subset, use = "pairwise.complete.obs")

# Print the correlation matrix
print(cor_matrix)
                    age body.weight      height    avg.sbp   avg.dbp cholestrol
age          1.00000000 -0.01377966 -0.08538971 0.55641362 0.1143690  0.2738272
body.weight -0.01377966  1.00000000  0.45314709 0.13693751 0.2900425  0.1032280
height      -0.08538971  0.45314709  1.00000000 0.01379185 0.2060106 -0.0631896
avg.sbp      0.55641362  0.13693751  0.01379185 1.00000000 0.5213667  0.2306877
avg.dbp      0.11436905  0.29004249  0.20601064 0.52136671 1.0000000  0.1706567
cholestrol   0.27382718  0.10322800 -0.06318960 0.23068766 0.1706567  1.0000000
corrplot(cor_matrix, method = "color", type = "upper", tl.col = "black", tl.cex = 0.8)

The most highly correlate features are age and average systolic blood pressure, body weight and height, average systolic blood pressure and average diastolic blood pressure, age and cholesterol, body weight and cholesterol, and body weigh and average diastolic blood pressure. The pairwise relationships are displayed with individual scatter plots.

# Set seed for reproducibility
set.seed(123)

# Bootstrap a smaller sample (adjust size as needed)
sample_indices <- sample(nrow(nhanes), size = 500, replace = TRUE)
sampled_data <- nhanes[sample_indices, ]

# Set up a 2x3 plotting grid
par(mfrow = c(2, 3))

# Scatterplot for Age and Avg. Systolic Blood Pressure
plot(sampled_data$age, sampled_data$avg.sbp, main = "Age vs Avg. Systolic BP", 
     xlab = "Age", ylab = "Avg. Systolic BP", col = "blue", pch = 19)

# Scatterplot for Body Weight and Height
plot(sampled_data$body.weight, sampled_data$height, main = "Body Weight vs Height", 
     xlab = "Body Weight", ylab = "Height", col = "red", pch = 19)

# Scatterplot for Avg. Systolic Blood Pressure and Avg. Diastolic Blood Pressure
plot(sampled_data$avg.sbp, sampled_data$avg.dbp, main = "Avg. Systolic vs Avg. Diastolic BP", 
     xlab = "Avg. Systolic BP", ylab = "Avg. Diastolic BP", col = "forestgreen", pch = 19)

# Scatterplot for Age and Cholesterol
plot(sampled_data$age, sampled_data$cholestrol, main = "Age vs Cholesterol", 
     xlab = "Age", ylab = "Cholesterol", col = "purple", pch = 19)

# Scatterplot for Avg. Systolic BP and Cholesterol
plot(sampled_data$avg.sbp, sampled_data$cholestrol, main = "Avg Systolic BP vs Cholesterol", 
     xlab = "Cholesterol", ylab = "Avg.SBP", col = "gold", pch = 19)

# Scatterplot for Body Weight and Avg. Diastolic Blood Pressure
plot(sampled_data$body.weight, sampled_data$avg.dbp, main = "Body Weight vs Avg. Diastolic BP", 
     xlab = "Body Weight", ylab = "Avg. Diastolic BP", col = "maroon", pch = 19)

Six of the most correlated pairwise relationship are visualized in scatter plots. All pairwise relationships are linear with no apparent clustering.

# Set up a 2x2 plotting grid
par(mfrow = c(2, 2))

# Create a contingency table
sex_hbp_table <- table(nhanes$sex, nhanes$hbp)

# Generate mosaic plot
mosaicplot(sex_hbp_table, 
           col = c("gold", "royalblue"), 
           main = "Sex and High Blood Pressure",
           xlab = "Sex Status", 
           ylab = "HBP Status",
           border = "black")


# Create a contingency table
race_hbp_table <- table(nhanes$race, nhanes$hbp)

# Generate mosaic plot
mosaicplot(race_hbp_table, 
           col = c("gold", "royalblue"), 
           main = "Race and High Blood Pressure",
           xlab = "Race", 
           ylab = "HBP Status",
           border = "black")


# Create a contingency table
current.smk_hbp_table <- table(nhanes$current.smk, nhanes$hbp)

# Generate mosaic plot
mosaicplot(current.smk_hbp_table, 
           col = c("gold", "royalblue"), 
           main = "Current Smoking Status and HBP",
           xlab = "Current Smoking Status", 
           ylab = "HBP Status",
           border = "black")


# Create a contingency table
past.smk_hbp_table <- table(nhanes$past.smk, nhanes$hbp)

# Generate mosaic plot
mosaicplot(past.smk_hbp_table, 
           col = c("gold", "royalblue"), 
           main = "Past Smoking Status and HBP",
           xlab = "Past Smoking Status", 
           ylab = "HBP Status",
           border = "black")

Relationship between high blood pressure and race, sex, and current smoking status can be visualized in the mosaic plots. There appears to be an association between high current smoking and race with high blood pressure. A less pronounced relationship can been seen between sex and race with high blood pressure.

# Set up a 2x2 plotting grid
par(mfrow = c(1, 2))


# Create a contingency table
current.smk_race_table <- table(nhanes$race, nhanes$current.smk)

# Generate mosaic plot
mosaicplot(current.smk_race_table, 
           col = c("gold", "royalblue"), 
           main = "Race and Current Smoke Status",
           xlab = "Race", 
           ylab = "Current Smoke",
           border = "black")


# Create a contingency table
current.smk_sex_table <- table(nhanes$sex, nhanes$current.smk)

# Generate mosaic plot
mosaicplot(current.smk_sex_table, 
           col = c("gold", "royalblue"), 
           main = "Sex and Current Smoke Status",
           xlab = "Sex", 
           ylab = "Current Smoke",
           border = "black")

# Create a contingency table
past.smk_race_table <- table(nhanes$race, nhanes$past.smk)

An association exists between race and current smoking. Black individuals tend to smoke more than white or other individuals. An association exists between sex and current smoke status. Female tend to smoke currently slight more than males in this population.

3 MISSING VALUES

3.1 Imputation for Categorical Features

The distribution of missing values for is examined to determine any patterns. This step is done to ensure that value are missing at random.

# Set up a 2x2 plotting grid
par(mfrow = c(2, 2))

#sum(is.na(nhanes$race))

#mean(is.na(nhanes$race))

#table(nhanes$race, useNA = "ifany")


#ggplot(nhanes, aes(x = factor(race))) +
  #geom_bar(fill = "blue") +
  #labs(title = "Distribution of Race (Before Imputation)", x = "Race", y = "Count") +
  #theme_minimal()


aggr(nhanes, col = c("navyblue", "red"), numbers = TRUE, sortVars = TRUE, 
     labels = names(nhanes), cex.axis = 0.7, gap = 2, 
     ylab = c("Missing Data Overview", "Pattern of Missing Data"))


 Variables sorted by number of missings: 
    Variable     Count
        race 0.1499937
  cholestrol 0.1499937
 body.weight 0.1400278
           X 0.0000000
         obs 0.0000000
         psu 0.0000000
     stratum 0.0000000
 stat.weight 0.0000000
         age 0.0000000
         sex 0.0000000
      height 0.0000000
     avg.sbp 0.0000000
     avg.dbp 0.0000000
    past.smk 0.0000000
 current.smk 0.0000000
         hbp 0.0000000

A pattern of missing values exists between body weight, BMI, and obese. This pattern can be explained by the fact that body weight is used to calculate BMI, which is then used to classify observations for obese. However, the pattern of missing value appears to be random for the other features.

No pattern of missing values exists between race and other features, In turn, kNN imputation is used for missing values of race.

sum(is.na(nhanes$race))
[1] 1189
table(nhanes$race, useNA = "ifany")  # Check distribution including NAs

White Black Other  <NA> 
 4693  1858   187  1189 
# Perform KNN Imputation (single imputation)
nhanes_imputed <- kNN(nhanes, variable = "race", k = 3)

# Keep only the original columns (without extra columns added by kNN)
nhanes_imputed <- nhanes_imputed[, names(nhanes)]



# COMPARE before and after imputation distribution

par(mfrow = c(1,2))  # Split plotting area into two

# Convert race to a factor for better visualization
nhanes$race <- as.factor(nhanes$race)
nhanes_imputed$race <- as.factor(nhanes_imputed$race)

# Create a new column to indicate whether the data is original or imputed
nhanes$source <- "Before Imputation"
nhanes_imputed$source <- "After Imputation"

# Combine both datasets
nhanes_compare <- bind_rows(nhanes, nhanes_imputed)

# Plot the distribution before and after imputation
ggplot(nhanes_compare, aes(x = race, fill = source)) +
  geom_bar(position = "dodge") +
  labs(title = "Distribution of Race Before and After Imputation",
       x = "Race",
       y = "Count",
       fill = "Dataset") +
  theme_minimal()

imputed_nhanes <- nhanes_imputed

The overall distribution of race after imputation changed slightly after imputation.

3.2 Regression-Based Imputation for Numerical Feature

The pattern of missing values for body weight and cholesterol is examined for any potential patterns.

#vis_miss(nhanes[, c("body.weight", "cholestrol")])


# Set smaller font size for the plot
par(cex = 0.4)  # Adjust this value for desired font size

# Generate the missing data pattern plot

md.pattern(imputed_nhanes)

     X obs psu stratum stat.weight age sex race height avg.sbp avg.dbp past.smk
5792 1   1   1       1           1   1   1    1      1       1       1        1
1025 1   1   1       1           1   1   1    1      1       1       1        1
946  1   1   1       1           1   1   1    1      1       1       1        1
164  1   1   1       1           1   1   1    1      1       1       1        1
     0   0   0       0           0   0   0    0      0       0       0        0
     current.smk hbp source body.weight cholestrol     
5792           1   1      1           1          1    0
1025           1   1      1           1          0    1
946            1   1      1           0          1    1
164            1   1      1           0          0    2
               0   0      0        1110       1189 2299
# Reset graphics settings (optional)
par(cex = 1)

A pattern of missing values exists between body weight, BMI, and obese because

Body weight is correlated with height, average diastolic blood pressure, and sex. In turn, the missing body weight values will be imputed using a regression model using said explanatory features.

# Subset nhanes to contain only complete observations for selected variables
complete_nhanes <- imputed_nhanes[complete.cases(imputed_nhanes[, c("body.weight", "height", "avg.dbp", "sex")]), ]

# Fit the linear regression model
model_body.weight <- lm(body.weight ~ height + avg.dbp + sex, data = complete_nhanes)

# View the model summary
summary(model_body.weight)

Call:
lm(formula = body.weight ~ height + avg.dbp + sex, data = complete_nhanes)

Residuals:
    Min      1Q  Median      3Q     Max 
-86.131 -22.276  -4.259  17.073 269.863 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept) -207.90214    9.27828 -22.407  < 2e-16 ***
height         4.86582    0.14277  34.080  < 2e-16 ***
avg.dbp        0.76728    0.03913  19.606  < 2e-16 ***
sexMale       -7.00000    1.07917  -6.486  9.4e-11 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 33.52 on 6813 degrees of freedom
Multiple R-squared:  0.2495,    Adjusted R-squared:  0.2491 
F-statistic: 754.9 on 3 and 6813 DF,  p-value: < 2.2e-16
# Plot the residuals
plot(model_body.weight$residuals)

The residual plot shows no patterns. In turn, the model fit the data well and the assumption of constant variance of residuals is satisfied.

# Create a copy of the dataset to work with
#imputed_nhanes <- complete_nhanes

colSums(is.na(imputed_nhanes))
          X         obs         psu     stratum stat.weight         age 
          0           0           0           0           0           0 
        sex        race body.weight      height     avg.sbp     avg.dbp 
          0           0        1110           0           0           0 
   past.smk current.smk  cholestrol         hbp      source 
          0           0        1189           0           0 
# Identify the rows with missing values for body.weight
missing_body_weight <- is.na(imputed_nhanes$body.weight)

# Use the model to predict the missing values
imputed_nhanes$body.weight[missing_body_weight] <- predict(model_body.weight, 
                                                           newdata = imputed_nhanes[missing_body_weight, c("height", "avg.dbp", "sex", "age")])

# Check the dataset
#head(imputed_nhanes)

# Create a plot to overlay the density curves
ggplot() +
  geom_density(data = complete_nhanes, aes(x = body.weight), fill = "blue", alpha = 0.2, na.rm = TRUE) + 
  geom_density(data = imputed_nhanes, aes(x = body.weight), fill = "red", alpha = 0.2, na.rm = TRUE) +
  labs(title = "Density Plot of Body Weight: Before and After Imputation",
       x = "Body Weight", y = "Density") +
  theme_minimal() +
  scale_fill_manual(name = "Body Weight", values = c("blue" = "blue", "red" = "red"), 
                    labels = c("Before Imputation", "After Imputation"))

The distribution before and after imputation is similar. In turn, the imputation did not change the distribution of body weight.

The features that are most correlated to cholesterol are age, average systolic blood pressure, and body weight. In turn, the missing values of cholesterol will be imputed with a model using these features.

# Subset nhanes to include only rows with complete cases for cholestrol, age, avg.sbp, and BMI
complete_nhanes <- imputed_nhanes[!is.na(imputed_nhanes$cholestrol) & !is.na(imputed_nhanes$age) & 
                           !is.na(imputed_nhanes$avg.sbp) & !is.na(imputed_nhanes$body.weight), ]

complete_nhanes <- imputed_nhanes[complete.cases(imputed_nhanes[, c("cholestrol", "age", "avg.sbp", "body.weight")]), ]

# Fit the linear regression model to predict cholestrol
model_cholestrol <- lm(cholestrol ~ age + avg.sbp + body.weight, data = complete_nhanes)
summary(model_cholestrol)

Call:
lm(formula = cholestrol ~ age + avg.sbp + body.weight, data = complete_nhanes)

Residuals:
    Min      1Q  Median      3Q     Max 
-162.16  -28.18   -3.08   24.08  498.54 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) 135.10667    3.96327  34.090  < 2e-16 ***
age           0.54613    0.03465  15.762  < 2e-16 ***
avg.sbp       0.21908    0.03267   6.707 2.15e-11 ***
body.weight   0.10341    0.01437   7.198 6.76e-13 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 42.59 on 6734 degrees of freedom
Multiple R-squared:  0.09077,   Adjusted R-squared:  0.09037 
F-statistic: 224.1 on 3 and 6734 DF,  p-value: < 2.2e-16
# View the model summary
summary(model_cholestrol)

Call:
lm(formula = cholestrol ~ age + avg.sbp + body.weight, data = complete_nhanes)

Residuals:
    Min      1Q  Median      3Q     Max 
-162.16  -28.18   -3.08   24.08  498.54 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) 135.10667    3.96327  34.090  < 2e-16 ***
age           0.54613    0.03465  15.762  < 2e-16 ***
avg.sbp       0.21908    0.03267   6.707 2.15e-11 ***
body.weight   0.10341    0.01437   7.198 6.76e-13 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 42.59 on 6734 degrees of freedom
Multiple R-squared:  0.09077,   Adjusted R-squared:  0.09037 
F-statistic: 224.1 on 3 and 6734 DF,  p-value: < 2.2e-16
# Create a copy of nhanes for imputation
#imputed_nhanes <- nhanes

# Identify rows with missing cholestrol values
missing_cholestrol <- is.na(imputed_nhanes$cholestrol)

# Use the model to predict the missing cholestrol values
imputed_nhanes$cholestrol[missing_cholestrol] <- predict(model_cholestrol, 
                                                          newdata = imputed_nhanes[missing_cholestrol, c("age", "avg.sbp", "body.weight")])

All explanatory features are significant.

# Get residuals from the model for complete_nhanes
residuals_cholestrol <- residuals(model_cholestrol)

# Predicted values for complete_nhanes
predicted_cholestrol <- predict(model_cholestrol, newdata = complete_nhanes)

# Create a data frame for residuals and predicted values
residuals_data <- data.frame(
  predicted_cholestrol = predicted_cholestrol,
  residuals_cholestrol = residuals_cholestrol
)

# Create the residual plot
library(ggplot2)
ggplot(residuals_data, aes(x = predicted_cholestrol, y = residuals_cholestrol)) +
  geom_point(color = "blue") +  # Plot the residuals
  geom_hline(yintercept = 0, linetype = "dashed", color = "red") +  # Add a horizontal line at 0
  labs(title = "Residual Plot for Cholestrol Prediction",
       x = "Predicted Cholestrol",
       y = "Residuals") +
  theme_minimal()

# Create the overlay density plot
ggplot() +
  geom_density(data = nhanes, aes(x = cholestrol), fill = "blue", alpha = 0.2, na.rm = TRUE) +  # Before imputation
  geom_density(data = imputed_nhanes, aes(x = cholestrol), fill = "red", alpha = 0.2, na.rm = TRUE) +  # After imputation
  labs(title = "Density Plot of Cholestrol: Before and After Imputation",
       x = "Cholestrol", y = "Density") +
  theme_minimal() +
  scale_fill_manual(name = "Cholestrol", values = c("blue" = "blue", "red" = "red"), 
                    labels = c("Before Imputation", "After Imputation"))

The distribution of cholesterol did not change significantly after imputation. As well, the residual plot does not display any patterns. In turn, the model fit the data well and the assumption of constant variance of residuals is satisfied.

3.3 Feature Engineer

In turn a feature which calculates BMI is created to determine observations are classified as obese. According to the CDC (https://www.cdc.gov/nccdphp/dnpao/data-trends-maps/help/npao_dtm/definitions.html), Adult obesity is defined as body mass index (BMI) ≥ 30.0. Another feature named obese, based on BMI, is created, where 0 = no and 1 = yes.

# Create BMI feature
imputed_nhanes$BMI <- (imputed_nhanes$body.weight * 703) / (imputed_nhanes$height * imputed_nhanes$height)
# Round the BMI to the nearest ones place
imputed_nhanes$BMI <- round(imputed_nhanes$BMI, 0)

# Create the obese feature based on BMI
imputed_nhanes$obese <- ifelse(imputed_nhanes$BMI >= 30, 1, 0)
par(mfrow = c(1, 2))

# Histogram for BMI

hist(imputed_nhanes$BMI, 
     main = "Histogram of BMI", 
     xlab = "BMI", 
     col = "steelblue", 
     border = "black", 
     breaks = 20)

# bar chart for obese
nhanes$obese <- factor(imputed_nhanes$obese, levels = c(0, 1), labels = c("No", "Yes"))

obese_count <- table(imputed_nhanes$obese)

barplot(height = obese_count, col = "steelblue", main = "Obesity", xlab = "Obesity", ylab = "Count")

# Set up a 2x2 plotting grid
par(mfrow = c(2, 2))


# Create a contingency table
obese_hbp_table <- table(imputed_nhanes$obese, imputed_nhanes$hbp)

# Generate mosaic plot
mosaicplot(obese_hbp_table, 
           col = c("gold", "royalblue"), 
           main = "Obesity and High Blood Pressure",
           xlab = "Obesity Status", 
           ylab = "HBP Status",
           border = "black")

# Create a contingency table
obese_sex_table <- table(imputed_nhanes$sex, imputed_nhanes$obese)

# Generate mosaic plot
mosaicplot(obese_sex_table, 
           col = c("gold", "royalblue"), 
           main = "Sex and Obesity",
           xlab = "Obesity Status", 
           ylab = "Sex",
           border = "black")


# Create a contingency table
obese_race_table <- table(imputed_nhanes$race, imputed_nhanes$obese)

# Generate mosaic plot
mosaicplot(obese_race_table, 
           col = c("gold", "royalblue"), 
           main = "Race and Obesity",
           xlab = "Obesity Status", 
           ylab = "Race",
           border = "black")


# Create a contingency table
obese_smoke_table <- table(imputed_nhanes$current.smk, imputed_nhanes$obese)

# Generate mosaic plot
mosaicplot(obese_smoke_table, 
           col = c("gold", "royalblue"), 
           main = "Current Smoking Status and Obesity",
           xlab = "Obesity Status", 
           ylab = "Current Smoking Status",
           border = "black")

3.4 Multiple Imputation

Multiple Imputation by Chained Equations (MICE) is a powerful technique used to handle missing data by creating multiple plausible imputations for each missing value based on relationships in the observed data. For body weight, cholesterol, and race, MICE can be applied to generate accurate imputations, accounting for correlations between these variables and other features in the dataset. This method allows for more reliable statistical analyses by reducing bias and preserving variability in the imputed values, making it especially useful for handling missing data in incoming new data sets.

nhanes1$race <- as.factor(nhanes1$race)  
nhanes1$cholestrol <- as.numeric(nhanes1$cholestrol)
nhanes1$body.weight <- as.numeric(nhanes1$body.weight)

nhanes2 <- nhanes1


# 1 initialization

init <- mice(nhanes2, maxit=0)
print(init$method)
          X         obs         psu     stratum stat.weight         age 
         ""          ""          ""          ""          ""          "" 
        sex        race body.weight      height     avg.sbp     avg.dbp 
         ""   "polyreg"       "pmm"          ""          ""          "" 
   past.smk current.smk  cholestrol         hbp 
         ""          ""       "pmm"          "" 
# 2 imputation models

imp <- mice(nhanes2, method = c("", "", "", "", "", "", "", "polyreg", "pmm", "", "", "", "", "", "pmm", ""), 
            maxit=10,
            m=1,
            seed = 123,
            print=F)

complete(imp, action = 1)[1:10,]
    X obs psu stratum stat.weight age sex race body.weight height avg.sbp
1   3   9   2      43    19451.83  48   0    1       149.7   61.8     131
2   5  11   2      40     1245.52  48   1    1       155.3   66.2     120
3   6  19   1      35     3860.97  44   1    2       189.6   70.2     133
4   7  34   1      13     5031.70  42   0    2       125.8   62.6     100
5  10  48   1      24    26919.29  56   0    1       239.9   67.6     128
6  12  51   1      28     2730.56  44   1    1       317.9   71.1     130
7  15  55   2      44      804.03  48   1    1       245.6   68.0     155
8  19  70   1       9     2629.39  63   1    2       202.9   67.8     137
9  20  71   1      43     1147.32  37   0    1       151.7   61.7     128
10 22  73   1      29     3991.81  42   1    3       205.0   68.4     148
   avg.dbp past.smk current.smk cholestrol hbp
1       73        1           2        236   0
2       70        1           2        260   0
3       85        1           1        187   0
4       67        1           1        216   0
5       73        1           2        156   0
6       86        1           1        162   0
7       91        1           1        212   1
8       68        1           1        186   0
9       70        1           1        209   0
10      83        1           1        267   1
# 3 multiple (iterative) imputations

imp5 <- mice(nhanes2, method = "pmm", m = 5, maxit = 10, seed = 123, print=F)
plot(imp5)

Multiple Imputation by Chained Equations (MICE) will be applied to handle missing values in the body weight variable. To assess the quality of the imputations, the Mean Squared Error (MSE) will be calculated and compared the MSE of the single imputation conducted for body weight earlier in this analysis, providing a measure of the imputation accuracy.

model5_bodyweight <- with(imp5, lm(body.weight ~ height + avg.dbp + sex))
summary.stats = summary(model5_bodyweight)

summary(pool(model5_bodyweight))
         term     estimate  std.error  statistic        df       p.value
1 (Intercept) -205.7045484 8.74935482 -23.510825 2473.3145 1.747163e-110
2      height    4.8466598 0.13536721  35.803796 1634.9416 8.934110e-208
3     avg.dbp    0.7523449 0.03941721  19.086712  157.8342  7.501512e-43
4         sex   -6.6078962 1.06330598  -6.214482  276.0479  1.892089e-09
beta = summary.stats$estimate[seq(1,15,by=3)]  # explicit vector: c(1,4,7,10,13)
beta.var = (summary.stats$std.error[seq(1,15,by=3)])^2 
Q = mean(beta)
U = mean(beta.var)
B = var(beta)
T = U + (6/5)*B
pool.se = sqrt(T)
cbind(pool.se.intercept = pool.se)
     pool.se.intercept
[1,]          123.2177

The model can be used to predict body weight for incoming new data.

The MSE for single body weight imputation used earlier in this analysis is MSE = (RSE)^2 = (33.52)^2 = 1123.6 which is substantially higher than MSE when using MICE. In turn, MICE is recommended in this analysis.

Multiple Imputation by Chained Equations (MICE) will be applied to handle missing values in the cholesterol variable. To assess the quality of the imputations, the Mean Squared Error (MSE) will be calculated and compared the MSE of the single imputation conducted for cholesterol earlier in this analysis, providing a measure of the imputation accuracy.

model5_chol <- with(imp5, lm(cholestrol ~ age + avg.sbp))
summary.stats = summary(model5_chol)


summary(pool(model5_chol))
         term    estimate  std.error statistic        df      p.value
1 (Intercept) 148.6912121 3.65965489 40.629845  74.24158 1.827860e-52
2         age   0.5233278 0.03407744 15.357017 236.74859 2.129193e-37
3     avg.sbp   0.2585339 0.03425598  7.547118  63.62530 2.094322e-10
beta = summary.stats$estimate[seq(1,15,by=3)]  # explicit vector: c(1,4,7,10,13)
beta.var = (summary.stats$std.error[seq(1,15,by=3)])^2 
Q = mean(beta)
U = mean(beta.var)
B = var(beta)
T = U + (6/5)*B
pool.se = sqrt(T)
cbind(pool.se.intercept = pool.se)
     pool.se.intercept
[1,]          3.659655

The model can be used to predict cholesterol for incoming new data.

The Mean Squared Error (MSE) from the Residual Standard Error (RSE) given in the model output from the cholesterol single imputation method used early in this analysis is MSE = (42.59)^2 = 1813.9. Thus, the Mean Squared Error (MSE) = 1813.9.

The MSE using MICE is 3.66 which is substantially less. Therefore, MICE is recommended in the analysis of this data set.

For the missing values in the race variable, Multiple Imputation by Chained Equations (MICE) will be applied using multinomial logistic regression. This method will account for the categorical nature of the race variable, allowing for appropriate imputation based on the relationships with other features in the dataset.

model_race <- with(imp5, multinom(race ~ avg.dbp + avg.sbp + cholestrol + hbp))
# weights:  18 (10 variable)
initial  value 8708.699612 
iter  10 value 5523.235718
final  value 5495.930272 
converged
# weights:  18 (10 variable)
initial  value 8708.699612 
iter  10 value 5555.595871
final  value 5522.606318 
converged
# weights:  18 (10 variable)
initial  value 8708.699612 
iter  10 value 5555.946819
final  value 5529.649391 
converged
# weights:  18 (10 variable)
initial  value 8708.699612 
iter  10 value 5560.173296
final  value 5529.439901 
converged
# weights:  18 (10 variable)
initial  value 8708.699612 
iter  10 value 5542.550592
final  value 5510.127472 
converged
# Pool the results from the imputed datasets
pooled_race <- pool(model_race)

# Get a summary of the pooled results
summary(pooled_race)
          term     estimate    std.error  statistic         df      p.value
1  (Intercept) -1.277932787 0.3325448882 -3.8428881   49.56081 3.468517e-04
2      avg.dbp  0.030728414 0.0030785469  9.9814670  343.89941 9.007490e-21
3      avg.sbp -0.009072042 0.0025775079 -3.5196952  252.21602 5.124609e-04
4   cholestrol -0.004119817 0.0007738102 -5.3240668   28.44201 1.091924e-05
5          hbp  0.148914062 0.1127433356  1.3208236  101.89054 1.895191e-01
6  (Intercept) -2.575346290 0.9149529588 -2.8147308   40.55536 7.498473e-03
7      avg.dbp  0.019877690 0.0080743228  2.4618399 3279.39165 1.387374e-02
8      avg.sbp -0.007708776 0.0071499482 -1.0781583  208.24247 2.822104e-01
9   cholestrol -0.005554712 0.0020814684 -2.6686508   36.04555 1.134283e-02
10         hbp -0.151093362 0.3197542727 -0.4725296  109.96948 6.374852e-01

The model can be used to predict race for incoming new data.

4 FEATURE TRANSFORMING

Based on the distribution patterns observed in the NHANES data set, several feature engineering tasks can be performed to enhance the data’s usability for modeling. First, for age, which is roughly uniform, no major transformation is needed, though we may consider binning it into age groups if it helps with interpretability. For weight and systolic blood pressure (BP), which are both skewed right, a log transformation could be applied to reduce skewness and make these variables more normally distributed, improving model performance. Similarly, for cholesterol, which is slightly skewed right, a log transformation may also be useful. For diastolic BP, which is roughly symmetric, no transformation is necessary, but checking for outliers could be helpful. These transformations aim to stabilize variance, reduce the impact of extreme values, and create features that are more suitable for modeling with techniques like linear regression or other statistical methods.

#Log transformation to reduce skew

imputed_nhanes$log_body.weight <- log(imputed_nhanes$body.weight)
imputed_nhanes$log_avg.sbp <- log(imputed_nhanes$avg.sbp)
imputed_nhanes$log_cholestrol <- log(imputed_nhanes$cholestrol)
imputed_nhanes$log_BMI <- log(imputed_nhanes$BMI)




# Set up the plotting area to show 2x2 grid of histograms
par(mfrow = c(2, 2))  # This will create a 2x2 grid of plots

# Histogram for Log-Cholesterol
hist(imputed_nhanes$log_cholestrol, 
     main = "Histogram of Log(Cholesterol)", 
     xlab = "Log(Cholesterol)", 
     col = "steelblue", 
     border = "black", 
     breaks = 20)  
    
# Histogram for Log-Body Weight
hist(imputed_nhanes$log_body.weight, 
     main = "Histogram of Log(Body Weight)", 
     xlab = "Log(Body Weight)", 
     col = "steelblue", 
     border = "black", 
     breaks = 20) 


# Histogram for Log-Systolic BP
hist(imputed_nhanes$log_avg.sbp, 
     main = "Histogram of Log(Systolic BP)", 
     xlab = "Log(Systolic BP)", 
     col = "steelblue", 
     border = "black", 
     breaks = 20)
   

# Histogram for Log-BMI
hist(imputed_nhanes$log_BMI, 
     main = "Histogram of Log(BMI)", 
     xlab = "Log(BMI)", 
     col = "steelblue", 
     border = "black", 
     breaks = 20)

The distributions of these previously skewed features are more symmetric after log transformations.

5 STANDARDIZING

Standardizing features ensures that variables with different scales, such as age, BMI, height, and cholesterol, contribute equally to the analysis. Without standardization, variables with larger ranges could dominate model performance, leading to biased results. By standardizing these features, we improve model accuracy, enable better comparison between variables, and enhance the efficiency of machine learning algorithms, particularly in models that rely on distance-based or gradient-based methods.

# Specify the columns to be standardized
columns_to_standardize <- c("age", "BMI", "height", "body.weight", "cholestrol", "avg.dbp", "avg.sbp")

# Standardize the selected columns
imputed_nhanes[columns_to_standardize] <- scale(imputed_nhanes[columns_to_standardize])

6 FEATURE SELECTION

Feature selection is a critical step in model building, as it helps improve model performance by identifying the most relevant predictors and reducing overfitting. In this analysis, both model-based selection and regularization-based selection techniques will be used to assess and retain the most influential features for accurate prediction, ensuring a more efficient and interpretable model.

A full model is created to predict cholesterol.

#sapply(imputed_nhanes, function(x) length(unique(x)))

#head(imputed_nhanes, 25)


#head(imputed_nhanes)


model_full <- lm(cholestrol ~ age + race + BMI + height + body.weight + 
                  hbp + avg.dbp + avg.sbp + obese, 
                  data = imputed_nhanes)

# Summary of the full model
#summary(model_full)

# Tidy the model summary
model_summary <- tidy(model_full)

# Calculate Mean Squared Error (MSE)
mse <- mean(model_full$residuals^2)

# Calculate R-squared
r2 <- summary(model_full)$r.squared

# Create a data frame for MSE and R-squared
metrics_df <- data.frame(Statistic = c("Mean Squared Error", "R-squared"), 
                         Value = c(mse, r2))

# Print the model summary using kable
kable(model_summary, digits = 3, caption = "Regression Model Summary")
Regression Model Summary
term estimate std.error statistic p.value
(Intercept) 0.043 0.017 2.447 0.014
age 0.250 0.013 18.847 0.000
raceBlack -0.068 0.024 -2.781 0.005
raceOther -0.206 0.067 -3.058 0.002
BMI -0.122 0.082 -1.477 0.140
height -0.190 0.049 -3.862 0.000
body.weight 0.266 0.093 2.847 0.004
hbp -0.066 0.042 -1.574 0.116
avg.dbp 0.116 0.013 8.774 0.000
avg.sbp 0.054 0.021 2.597 0.009
obese -0.022 0.038 -0.589 0.556
# Print MSE and R-squared using kable
kable(metrics_df, digits = 3, caption = "Model Performance Metrics")
Model Performance Metrics
Statistic Value
Mean Squared Error 0.876
R-squared 0.124

Stepwise model selection is conducted to retain significant predictors. Selection processes based on AIC and BIC are conducted.

# Stepwise model selection based on AIC
model_stepwise_AIC <- step(model_full, direction = "both", trace = 0)

# Stepwise model selection based on BIC
model_stepwise_BIC <- step(model_full, direction = "both", k = log(nrow(imputed_nhanes)), trace = 0)


# Tidy the summaries for both models
stepwise_AIC_summary <- tidy(model_stepwise_AIC)
stepwise_BIC_summary <- tidy(model_stepwise_BIC)

# Compute MSE for both models
mse_AIC <- mean(model_stepwise_AIC$residuals^2)
mse_BIC <- mean(model_stepwise_BIC$residuals^2)

# Compute R-squared for both models
r2_AIC <- summary(model_stepwise_AIC)$r.squared
r2_BIC <- summary(model_stepwise_BIC)$r.squared

# Create data frames for MSE and R-squared
metrics_AIC_df <- data.frame(Statistic = c("Mean Squared Error", "R-squared"), 
                             Value = c(mse_AIC, r2_AIC))

metrics_BIC_df <- data.frame(Statistic = c("Mean Squared Error", "R-squared"), 
                             Value = c(mse_BIC, r2_BIC))

# Print the stepwise AIC model summary
kable(stepwise_AIC_summary, digits = 3, caption = "Stepwise AIC Regression Model Summary")
Stepwise AIC Regression Model Summary
term estimate std.error statistic p.value
(Intercept) 0.038 0.015 2.462 0.014
age 0.250 0.013 18.875 0.000
raceBlack -0.068 0.024 -2.792 0.005
raceOther -0.206 0.067 -3.062 0.002
BMI -0.127 0.082 -1.553 0.121
height -0.188 0.049 -3.842 0.000
body.weight 0.264 0.093 2.829 0.005
hbp -0.067 0.042 -1.588 0.112
avg.dbp 0.117 0.013 8.778 0.000
avg.sbp 0.054 0.021 2.604 0.009
# Print performance metrics for AIC model
kable(metrics_AIC_df, digits = 3, caption = "Model Performance Metrics (AIC)")
Model Performance Metrics (AIC)
Statistic Value
Mean Squared Error 0.876
R-squared 0.124
# Print the stepwise BIC model summary
kable(stepwise_BIC_summary, digits = 3, caption = "Stepwise BIC Regression Model Summary")
Stepwise BIC Regression Model Summary
term estimate std.error statistic p.value
(Intercept) 0.000 0.011 0.000 1
age 0.271 0.011 25.433 0
height -0.116 0.012 -9.640 0
body.weight 0.122 0.012 9.908 0
avg.dbp 0.129 0.011 11.519 0
# Print performance metrics for BIC model
kable(metrics_BIC_df, digits = 3, caption = "Model Performance Metrics (BIC)")
Model Performance Metrics (BIC)
Statistic Value
Mean Squared Error 0.879
R-squared 0.121
# Check R-squared value
summary(model_stepwise_AIC)$r.squared
[1] 0.123777
summary(model_stepwise_BIC)$r.squared
[1] 0.1210105

Both AIC and BIC stepwise model selection processes have similar R squared values. The BIC stepwise model is parsimonious. This model selects age, height, body weight, and average diastolic blood pressure as predictors for cholesterol.

Regularization-based selection techniques are useful for improving model performance and preventing overfitting, especially when you have many predictors. Two common regularization methods are Ridge regression and Lasso regression.

# Extract the response and predictors
y <- imputed_nhanes$cholestrol  # Response variable
X <- as.matrix(imputed_nhanes[, c("age", "BMI", "height", "body.weight", "avg.dbp", "avg.sbp")])

# Optional: Scale predictors (recommended for Ridge and Lasso)
X_scaled <- scale(X)

# Fit Ridge and Lasso models
ridge_model <- glmnet(X_scaled, y, alpha = 0)  # Ridge Regression (alpha = 0)
lasso_model <- glmnet(X_scaled, y, alpha = 1)  # Lasso Regression (alpha = 1)

# Ridge cross-validation
cv_ridge <- cv.glmnet(X_scaled, y, alpha = 0)
best_lambda_ridge <- cv_ridge$lambda.min

# Lasso cross-validation
cv_lasso <- cv.glmnet(X_scaled, y, alpha = 1)
best_lambda_lasso <- cv_lasso$lambda.min

# Extract coefficients for Ridge and Lasso at optimal lambda
ridge_coefficients <- as.data.frame(as.matrix(coef(cv_ridge, s = "lambda.min")))
colnames(ridge_coefficients) <- c("Coefficient")
ridge_coefficients$Predictor <- rownames(ridge_coefficients)

lasso_coefficients <- as.data.frame(as.matrix(coef(cv_lasso, s = "lambda.min")))
colnames(lasso_coefficients) <- c("Coefficient")
lasso_coefficients$Predictor <- rownames(lasso_coefficients)

# Predictions for Ridge
pred_ridge <- predict(cv_ridge, X_scaled, s = "lambda.min")

# Predictions for Lasso
pred_lasso <- predict(cv_lasso, X_scaled, s = "lambda.min")

# Calculate RMSE for Ridge
rmse_ridge <- sqrt(mean((pred_ridge - y)^2))

# Calculate RMSE for Lasso
rmse_lasso <- sqrt(mean((pred_lasso - y)^2))

# Calculate R² for Ridge
rss_ridge <- sum((pred_ridge - y)^2)  # Residual Sum of Squares
tss_ridge <- sum((y - mean(y))^2)    # Total Sum of Squares
r2_ridge <- 1 - rss_ridge / tss_ridge

# Calculate R² for Lasso
rss_lasso <- sum((pred_lasso - y)^2)
tss_lasso <- sum((y - mean(y))^2)
r2_lasso <- 1 - rss_lasso / tss_lasso

# Create a data frame for RMSE and R²
metrics_df <- data.frame(
  Model = c("Ridge", "Lasso"),
  RMSE = c(rmse_ridge, rmse_lasso),
  R2 = c(r2_ridge, r2_lasso)
)

# Print Ridge coefficients using kable
kable(ridge_coefficients, digits = 3, caption = "Ridge Regression Coefficients")
Ridge Regression Coefficients
Coefficient Predictor
(Intercept) 0.000 (Intercept)
age 0.245 age
BMI 0.041 BMI
height -0.086 height
body.weight 0.071 body.weight
avg.dbp 0.109 avg.dbp
avg.sbp 0.039 avg.sbp
# Print Lasso coefficients using kable
kable(lasso_coefficients, digits = 3, caption = "Lasso Regression Coefficients")
Lasso Regression Coefficients
Coefficient Predictor
(Intercept) 0.000 (Intercept)
age 0.255 age
BMI 0.000 BMI
height -0.113 height
body.weight 0.120 body.weight
avg.dbp 0.114 avg.dbp
avg.sbp 0.030 avg.sbp
# Print RMSE and R² values using kable
kable(metrics_df, digits = 3, caption = "Model Performance Metrics (RMSE & R²)")
Model Performance Metrics (RMSE & R²)
Model RMSE R2
Ridge 0.937 0.121
Lasso 0.937 0.121

The Ridge and Lasso method both had similar R squared values. Therefore, both models are recommended.

7 LINEAR REGRESSION

In this regression analysis of the NHANES dataset, three models are developed using cross validation to predict the outcome variable cholesterol: a full model including all selected predictors, a stepwise BIC model for variable selection, and a Ridge regression model to address multicollinearity. Each model was evaluated based on its predictive performance, with Mean Squared Error (MSE) and R-squared (R^2) used as key comparison metrics. By analyzing these models, the aim is to determine the most accurate and efficient approach for modeling the data while balancing complexity and predictive power.

set.seed(42)
train_control <- trainControl(method = "cv", number = 10)

7.1 Full Model

The full model includes all selected predictor variables, providing a comprehensive approach to estimating cholesterol levels. To assess its stability, we implement k-fold cross-validation, which systematically partitions the dataset into multiple training and validation subsets. This approach mitigates the risk of overfitting by testing the model’s performance on unseen data, yielding a robust estimate of prediction error. The model’s effectiveness is quantified using the Mean Squared Error (MSE), which measures the average squared difference between observed and predicted cholesterol values. By employing cross-validation, we ensure that the full model is evaluated rigorously, providing insights into its accuracy and reliability in real-world applications.

# Set up 10-fold cross-validation
train_control <- trainControl(method = "cv", number = 10)  # 10-fold CV

# Fit the full model
full_model <- train(cholestrol ~ age + race + log_BMI + height + log_body.weight + 
                    hbp + avg.dbp + log_avg.sbp + obese, 
                    data = imputed_nhanes, 
                    method = "lm", 
                    trControl = train_control)

# Extract coefficients from the final model
coeff_table <- summary(full_model$finalModel)$coefficients %>%
  as.data.frame() %>%
  rownames_to_column(var = "Predictor")  # Convert row names to a column

# Calculate Cross-Validation MSE
mse <- mean(full_model$resample$RMSE^2)

# Calculate R² from the final model
r2 <- summary(full_model$finalModel)$r.squared

# Create a data frame for MSE and R²
metrics_df <- data.frame(
  Statistic = c("Mean Squared Error", "R-squared"),
  Value = c(mse, r2)
)

# Print the coefficients using kable
kable(coeff_table, digits = 4, caption = "Regression Model Coefficients", format = "markdown")
Regression Model Coefficients
Predictor Estimate Std. Error t value Pr(>|t|)
(Intercept) -4.5758 1.7615 -2.5977 0.0094
age 0.2434 0.0134 18.1921 0.0000
raceBlack -0.0679 0.0243 -2.7969 0.0052
raceOther -0.2054 0.0671 -3.0602 0.0022
log_BMI 0.6340 0.8695 0.7292 0.4659
height -0.0660 0.0975 -0.6772 0.4983
log_body.weight 0.1011 0.8701 0.1162 0.9075
hbp -0.0668 0.0403 -1.6602 0.0969
avg.dbp 0.1091 0.0134 8.1549 0.0000
log_avg.sbp 0.4214 0.1375 3.0636 0.0022
obese -0.0581 0.0367 -1.5830 0.1135
# Print MSE and R² using kable
kable(metrics_df, digits = 4, caption = "Model Performance Metrics (MSE & R²)", format = "markdown")
Model Performance Metrics (MSE & R²)
Statistic Value
Mean Squared Error 0.8762
R-squared 0.1266

7.2 Stepwise BIC

In this analysis, a Stepwise BIC regression model is implemented to identify the most parsimonious subset of predictors for estimating cholesterol levels. The Stepwise BIC approach selects variables by minimizing the Bayesian Information Criterion (BIC), which penalizes model complexity to prevent overfitting. To assess the model’s generalizability, we employ cross-validation by splitting the dataset into training and testing subsets. The model is trained on the training data, and predictions are made on the test data to compute the Mean Squared Error (MSE) as a measure of model performance. Additionally, the estimated regression coefficients in a structured table for clarity and interpretation. This approach ensures an optimal balance between model complexity and predictive accuracy while validating the model’s robustness.

stepwise_bic_model <- function(train_data, test_data) {
  # Fit initial full model
  full_model2 <- lm(cholestrol ~ age + height + log_body.weight + avg.dbp, data = train_data)
  
  # Perform stepwise selection using BIC
  model_stepwise_BIC <- stepAIC(full_model2, direction = "both", k = log(nrow(train_data)), trace = FALSE)
  
  # Extract coefficients
  coeff_table <- summary(model_stepwise_BIC)$coefficients %>%
    as.data.frame() %>%
    rownames_to_column(var = "Predictor")  # Convert row names to a column

  # Print coefficients using kable
  print(kable(coeff_table, digits = 4, caption = "Stepwise BIC Model Coefficients", format = "markdown"))

  # Predict on test data
  predictions <- predict(model_stepwise_BIC, newdata = test_data)
  
  # Compute Mean Squared Error (MSE)
  mse <- mean((test_data$cholestrol - predictions)^2)

  # Compute R²
  rss <- sum((test_data$cholestrol - predictions)^2)  # Residual Sum of Squares
  tss <- sum((test_data$cholestrol - mean(test_data$cholestrol))^2)  # Total Sum of Squares
  r2 <- 1 - rss/tss  # R-squared
  
  # Create a data frame for MSE and R²
  metrics_df <- data.frame(
    Statistic = c("Mean Squared Error", "R-squared"),
    Value = c(mse, r2)
  )

  # Print MSE and R² using kable
  print(kable(metrics_df, digits = 4, caption = "Stepwise BIC Model Performance Metrics (MSE & R²)", format = "markdown"))

  return(list(model = model_stepwise_BIC, mse = mse, r2 = r2))  # Return the model, MSE, and R²
}

# Example usage (Assuming you have a dataset split into train_data and test_data)
set.seed(123)
train_index <- createDataPartition(imputed_nhanes$cholestrol, p = 0.8, list = FALSE)
train_data <- imputed_nhanes[train_index, ]
test_data <- imputed_nhanes[-train_index, ]

# Run the function
stepwise_results <- stepwise_bic_model(train_data, test_data)


Table: Stepwise BIC Model Coefficients

|Predictor       | Estimate| Std. Error| t value| Pr(>&#124;t&#124;)|
|:---------------|--------:|----------:|-------:|------------------:|
|(Intercept)     |  -3.3622|     0.3416| -9.8427|                  0|
|age             |   0.2671|     0.0120| 22.2994|                  0|
|height          |  -0.1274|     0.0138| -9.2161|                  0|
|log_body.weight |   0.6589|     0.0669|  9.8520|                  0|
|avg.dbp         |   0.1191|     0.0125|  9.5632|                  0|


Table: Stepwise BIC Model Performance Metrics (MSE & R²)

|Statistic          |  Value|
|:------------------|------:|
|Mean Squared Error | 0.8383|
|R-squared          | 0.1425|

7.3 Ridge Regression

Ridge regression is applied to the NHANES dataset to address multicollinearity among predictor variables while maintaining model stability. By imposing a penalty on large coefficients through L2 regularization, Ridge regression prevents overfitting and improves generalization. The model was evaluated using cross-validation, and its performance was compared to other regression approaches based on Mean Squared Error (MSE) and R².

# Define predictor matrix (X) and response variable (y)
X <- as.matrix(imputed_nhanes[, c("age", "log_BMI", "height", "log_body.weight", "avg.dbp", "log_avg.sbp")])
y <- imputed_nhanes$cholestrol

set.seed(123)  # For reproducibility

# Define training control with 10-fold cross-validation
train_control <- trainControl(method = "cv", number = 10)

# Train Ridge Regression Model
ridge_model <- train(
  x = X, y = y,
  method = "glmnet",
  trControl = train_control,
  tuneGrid = expand.grid(alpha = 0, lambda = 10^seq(-3, 3, length = 100))  # Ridge: alpha = 0
)

# Best lambda value selected via cross-validation
best_lambda <- ridge_model$bestTune$lambda

# Predict using best lambda
ridge_predictions <- predict(ridge_model, X)

# Compute Mean Squared Error (MSE)
ridge_mse <- mean((y - ridge_predictions)^2)

# Compute R²
rss <- sum((y - ridge_predictions)^2)  # Residual Sum of Squares
tss <- sum((y - mean(y))^2)  # Total Sum of Squares
ridge_r2 <- 1 - (rss / tss)  # R² calculation

# Extract coefficients from the final Ridge model
coefficients <- as.data.frame(as.matrix(ridge_model$finalModel$beta)) %>%
  tibble::rownames_to_column(var = "Predictor")  # Convert row names to a column

#print(kable(head(coefficients, 10), digits = 4, caption = "Top 10 Ridge Regression Coefficients", format = "markdown"))


# Create a data frame for MSE, R², and Best Lambda
metrics_df <- data.frame(
  Statistic = c("Mean Squared Error", "R-squared", "Optimal Lambda"),
  Value = c(ridge_mse, ridge_r2, best_lambda)
)

# Print model performance metrics using kable()
print(kable(metrics_df, digits = 4, caption = "Ridge Regression Performance Metrics", format = "markdown"))


Table: Ridge Regression Performance Metrics

|Statistic          |  Value|
|:------------------|------:|
|Mean Squared Error | 0.8757|
|R-squared          | 0.1242|
|Optimal Lambda     | 0.0285|

7.4 Comparison

After performing cross-validation on the NHANES_imputed dataset, the predictive performance of the thre models are compared. The BIC model has the smallest MSE and highest R^2 value, indicating a better performing regression model. In, turn, the BIC model is recommended.

8 LOGISTIC REGRESSION

This analysis applies logistic regression to predict current smoking status using data from NHANES. Four models are developed: a full model including all relevant predictors, a stepwise AIC model for variable selection, a BIC model for a more parsimonious approach, and a regularized logistic regression model using Lasso to prevent overfitting. The models are evaluated and compared using Receiver Operating Characteristic (ROC) curves and the Area Under the Curve (AUC) to assess their classification performance and predictive accuracy.

8.1 Full Model

The first candidate, a full model, is fitted to predict current smoking status.

# Fit logistic regression model
full_model <- glm(current.smk ~ age + race + log_body.weight + log_BMI + obese + 
                    height + log_avg.sbp + avg.dbp + log_cholestrol + hbp, 
                  data = imputed_nhanes, 
                  family = binomial)

# Extract coefficients from the model
coefficients <- summary(full_model)$coefficients

# Convert coefficients to a data frame and add row names as a column
coeff_table <- as.data.frame(coefficients) %>%
  tibble::rownames_to_column(var = "Predictor")  # Convert row names to a column

# Print the coefficients table using kable
kable(coeff_table, digits = 4, caption = "Logistic Regression Model Coefficients", format = "markdown")
Logistic Regression Model Coefficients
Predictor Estimate Std. Error z value Pr(>|z|)
(Intercept) -9.6100 4.2576 -2.2571 0.0240
age 0.8518 0.0341 24.9430 0.0000
raceBlack -0.8473 0.0583 -14.5294 0.0000
raceOther -0.3106 0.1567 -1.9825 0.0474
log_body.weight 2.6402 2.0813 1.2685 0.2046
log_BMI -0.6406 2.0792 -0.3081 0.7580
obese -0.1208 0.0867 -1.3930 0.1636
height -0.2097 0.2330 -0.8999 0.3682
log_avg.sbp -0.4720 0.3284 -1.4375 0.1506
avg.dbp 0.0655 0.0324 2.0189 0.0435
log_cholestrol 0.1397 0.1348 1.0365 0.3000
hbp -0.0763 0.0957 -0.7975 0.4252

Age, race, and average dbp are significant features in the full model.

8.2 Stepwise AIC Model

The second model, stepwise AIC, is fitted to predict current smoking status. This model automatically selects a subset of predictors using AIC-based stepwise selection.

# Fit initial full model
full_model <- glm(current.smk ~ age + race + log_body.weight + log_BMI + obese + 
                    height + log_avg.sbp + avg.dbp + log_cholestrol + hbp, 
                  data = imputed_nhanes, 
                  family = binomial)

# Perform stepwise selection using AIC
stepwise_model <- stepAIC(full_model, direction = "both", trace = FALSE)

# Extract coefficients from the stepwise model
coefficients_stepwise <- summary(stepwise_model)$coefficients

# Convert coefficients to a data frame and add row names as a column
coeff_table_stepwise <- as.data.frame(coefficients_stepwise) %>%
  tibble::rownames_to_column(var = "Predictor")  # Convert row names to a column

# Print the coefficients table using kable
kable(coeff_table_stepwise, digits = 4, caption = "Stepwise Logistic Regression Model Coefficients", format = "markdown")
Stepwise Logistic Regression Model Coefficients
Predictor Estimate Std. Error z value Pr(>|z|)
(Intercept) -7.1104 1.5749 -4.5148 0.0000
age 0.8583 0.0335 25.6466 0.0000
raceBlack -0.8515 0.0582 -14.6232 0.0000
raceOther -0.3164 0.1565 -2.0212 0.0433
log_body.weight 2.0364 0.2072 9.8304 0.0000
obese -0.1260 0.0865 -1.4575 0.1450
height -0.1417 0.0341 -4.1583 0.0000
log_avg.sbp -0.6344 0.2525 -2.5125 0.0120
avg.dbp 0.0698 0.0323 2.1632 0.0305

All features, other than obese, are significant in the stepwise AIC model.

8.3 BIC Model

The third candidate,a BIC model, is fitted to predict current smoking status. This model fits a more parsimonious model.

# Fit initial full model
full_model <- glm(current.smk ~ age + race + log_body.weight + log_BMI + obese + 
                    height + log_avg.sbp + avg.dbp + log_cholestrol + hbp, 
                  data = imputed_nhanes, 
                  family = binomial)

# Perform stepwise selection using BIC (using k = log(nrow(imputed_nhanes)))
bic_model <- stepAIC(full_model, direction = "both", k = log(nrow(imputed_nhanes)), trace = FALSE)

# Extract coefficients from the BIC model
coefficients_bic <- summary(bic_model)$coefficients

# Convert coefficients to a data frame and add row names as a column
coeff_table_bic <- as.data.frame(coefficients_bic) %>%
  tibble::rownames_to_column(var = "Predictor")  # Convert row names to a column

# Print the coefficients table using kable
kable(coeff_table_bic, digits = 4, caption = "BIC Stepwise Model Coefficients", format = "markdown")
BIC Stepwise Model Coefficients
Predictor Estimate Std. Error z value Pr(>|z|)
(Intercept) -9.1460 0.7115 -12.8541 0.0000
age 0.8140 0.0268 30.3780 0.0000
raceBlack -0.8552 0.0579 -14.7775 0.0000
raceOther -0.3123 0.1562 -1.9988 0.0456
log_body.weight 1.8297 0.1394 13.1290 0.0000
height -0.1092 0.0290 -3.7669 0.0002

All features are significant in the BIC model.

8.4 Regularized Logistic Regression Model (Lasso)

The fourth candidate model uses Regularized Logistic Regression (Lasso). This method selects the most important predictors.

# Define predictor matrix (X) and response variable (y)
x <- model.matrix(current.smk ~ age + race + log_body.weight + log_BMI + obese + height + log_avg.sbp + avg.dbp + log_cholestrol + hbp, 
                  data = imputed_nhanes)[, -1]  # Exclude intercept
y <- imputed_nhanes$current.smk

# Train the Lasso model using cross-validation
lasso_model <- cv.glmnet(x, y, family = "binomial", alpha = 1)


# Best lambda value selected via cross-validation
best_lambda_lasso <- lasso_model$lambda.min
print(paste("Optimal Lambda for Lasso:", best_lambda_lasso))
[1] "Optimal Lambda for Lasso: 0.000783042982863974"
# Extract coefficients from the final Lasso model at the optimal lambda
lasso_coefficients <- coef(lasso_model, s = "lambda.min")

# Convert coefficients to a data frame
lasso_coefficients_df <- as.data.frame(as.matrix(lasso_coefficients))
lasso_coefficients_df$Predictor <- rownames(lasso_coefficients_df)

# Reorder columns to make predictor names the first column
lasso_coefficients_df <- lasso_coefficients_df %>%
  select(Predictor, everything())

# Print the coefficients table using kable
kable(lasso_coefficients_df, digits = 4, caption = "Lasso Regression Coefficients", format = "markdown")
Lasso Regression Coefficients
Predictor s1
(Intercept) (Intercept) -6.4108
age age 0.8393
raceBlack raceBlack -0.8379
raceOther raceOther -0.2843
log_body.weight log_body.weight 0.7797
log_BMI log_BMI 1.1279
obese obese -0.0866
height height 0.0000
log_avg.sbp log_avg.sbp -0.3598
avg.dbp avg.dbp 0.0546
log_cholestrol log_cholestrol 0.1316
hbp hbp -0.0746

8.5 Comparison

In this analysis, four logistic regression models—Full Model, Stepwise AIC Model, BIC Model, and Lasso Model are compared using ROC (Receiver Operating Characteristic) curves and AUC (Area Under the Curve) to assess their predictive performance. The optimal cutoff for each model using Youden’s Index is determined, which maximizes the balance between sensitivity and specificity. By evaluating these models through both graphical and numerical metrics, insights is gained into which model provides the best classification performance for predicting the outcome variable.

# Full Model
full_model <- glm(current.smk ~ age + race + log_body.weight + log_BMI + obese + height + log_avg.sbp + avg.dbp + log_cholestrol + hbp, data = imputed_nhanes, family = binomial)

# Stepwise AIC Model
stepwise_model <- stepAIC(full_model, direction = "both", trace = FALSE)

# BIC Model
bic_model <- stepAIC(full_model, direction = "both", k = log(nrow(imputed_nhanes)), trace = FALSE)

# Lasso Model
x <- model.matrix(current.smk ~ age + race + log_body.weight + log_BMI + obese + height + log_avg.sbp + avg.dbp + log_cholestrol + hbp , data = imputed_nhanes)[, -1]  # Exclude intercept
y <- imputed_nhanes$current.smk
lasso_cv <- cv.glmnet(x, y, family = "binomial", alpha = 1)
lasso_model <- glmnet(x, y, family = "binomial", alpha = 1, lambda = lasso_cv$lambda.min)

# Get predicted probabilities
imputed_nhanes$full_pred <- predict(full_model, type = "response")
imputed_nhanes$stepwise_pred <- predict(stepwise_model, type = "response")
imputed_nhanes$bic_pred <- predict(bic_model, type = "response")
imputed_nhanes$lasso_pred <- predict(lasso_model, newx = x, type = "response")[,1]

# Create ROC curves
full_roc <- roc(imputed_nhanes$current.smk, imputed_nhanes$full_pred)
stepwise_roc <- roc(imputed_nhanes$current.smk, imputed_nhanes$stepwise_pred)
bic_roc <- roc(imputed_nhanes$current.smk, imputed_nhanes$bic_pred)
lasso_roc <- roc(imputed_nhanes$current.smk, imputed_nhanes$lasso_pred)

# Calculate optimal cutoff using Youden's Index
optimal_cutoff_full <- full_roc$specificities[which.max(full_roc$sensitivities + full_roc$specificities - 1)]
optimal_cutoff_stepwise <- stepwise_roc$specificities[which.max(stepwise_roc$sensitivities + stepwise_roc$specificities - 1)]
optimal_cutoff_bic <- bic_roc$specificities[which.max(bic_roc$sensitivities + bic_roc$specificities - 1)]
optimal_cutoff_lasso <- lasso_roc$specificities[which.max(lasso_roc$sensitivities + lasso_roc$specificities - 1)]

# Print optimal cutoffs
cat("Optimal cutoff for Full Model:", optimal_cutoff_full, "\n")
Optimal cutoff for Full Model: 0.714215 
cat("Optimal cutoff for Stepwise AIC Model:", optimal_cutoff_stepwise, "\n")
Optimal cutoff for Stepwise AIC Model: 0.7191679 
cat("Optimal cutoff for BIC Model:", optimal_cutoff_bic, "\n")
Optimal cutoff for BIC Model: 0.7209014 
cat("Optimal cutoff for Lasso Model:", optimal_cutoff_lasso, "\n")
Optimal cutoff for Lasso Model: 0.7013373 
# Plot all ROC curves
ggplot() +
  geom_line(aes(x = full_roc$specificities, y = full_roc$sensitivities, color = "Full Model")) +
  geom_line(aes(x = stepwise_roc$specificities, y = stepwise_roc$sensitivities, color = "Stepwise AIC")) +
  geom_line(aes(x = bic_roc$specificities, y = bic_roc$sensitivities, color = "BIC Model")) +
  geom_line(aes(x = lasso_roc$specificities, y = lasso_roc$sensitivities, color = "Lasso Model")) +
  labs(title = "ROC Curve Comparison", x = "1 - Specificity", y = "Sensitivity") +
  scale_color_manual(values = c("red", "blue", "green", "purple", "orange")) +
  theme_minimal()

# AUC values
auc_values <- data.frame(
  Model = c("Full Model", "Stepwise AIC", "BIC Model", "Lasso Model"),
  AUC = c(auc(full_roc), auc(stepwise_roc), auc(bic_roc), auc(lasso_roc))
)

print(auc_values)
         Model       AUC
1   Full Model 0.7509937
2 Stepwise AIC 0.7507281
3    BIC Model 0.7496650
4  Lasso Model 0.7508550

All models have very similar AUC. In turn, the more parsimonious model, BIC, is recommended.

9 CONCLUSION

In this analysis, a comprehensive approach was taken to explore and model the NHANES dataset. Beginning with Exploratory Data Analysis (EDA), patterns and missing values were identified, leading to the implementation of Multiple Imputation by Chained Equations (MICE) to handle missing data. Feature engineering and transformation were applied to enhance model performance, followed by feature selection to refine predictor variables. Both linear and logistic regression models were developed and evaluated, including full models, stepwise selection methods, and regularized regression techniques. Ultimately, the Bayesian Information Criterion (BIC) emerged as the best-performing model for both linear and logistic regression, demonstrating its effectiveness in balancing model complexity and predictive accuracy.

LS0tCnRpdGxlOiAnQW5hbHlzaXMgb2YgVGhlIE5hdGlvbmFsIEhlYWx0aCBhbmQgTnV0cml0aW9uIEV4YW1pbmF0aW9uIFN1cnZleSAoTkhBTkVTKScKYXV0aG9yOiAiSm9hbm5lIE11c2EiCmRhdGU6ICJNYXJjaCA1LCAyMDI1IgpvdXRwdXQ6IAogIGh0bWxfZG9jdW1lbnQ6IAogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogNAogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICB0b2NfY29sbGFwc2VkOiB5ZXMKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgY29kZV9kb3dubG9hZDogeWVzCiAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMKICAgIHRoZW1lOiBsdW1lbgogIHdvcmRfZG9jdW1lbnQ6IAogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogNAogICAgZmlnX2NhcHRpb246IHllcwogICAga2VlcF9tZDogeWVzCiAgcGRmX2RvY3VtZW50OiAKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDQKICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICBmaWdfd2lkdGg6IDMKICAgIGZpZ19oZWlnaHQ6IDMKZWRpdG9yX29wdGlvbnM6IAogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUKLS0tCgpgYGB7PWh0bWx9Cgo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgoKLyogQ2FzY2FkaW5nIFN0eWxlIFNoZWV0cyAoQ1NTKSBpcyBhIHN0eWxlc2hlZXQgbGFuZ3VhZ2UgdXNlZCB0byBkZXNjcmliZSB0aGUgcHJlc2VudGF0aW9uIG9mIGEgZG9jdW1lbnQgd3JpdHRlbiBpbiBIVE1MIG9yIFhNTC4gaXQgaXMgYSBzaW1wbGUgbWVjaGFuaXNtIGZvciBhZGRpbmcgc3R5bGUgKGUuZy4sIGZvbnRzLCBjb2xvcnMsIHNwYWNpbmcpIHRvIFdlYiBkb2N1bWVudHMuICovCgpoMS50aXRsZSB7ICAvKiBUaXRsZSAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgb2YgdGhlIHJlcG9ydCB0aXRsZSAqLwogIGZvbnQtc2l6ZTogMjRweDsKICBjb2xvcjogRGFya1JlZDsKICB0ZXh0LWFsaWduOiBjZW50ZXI7CiAgZm9udC1mYW1pbHk6ICJHaWxsIFNhbnMiLCBzYW5zLXNlcmlmOwogIGZvbnQtd2VpZ2h0OiBib2xkOwp9Cmg0LmF1dGhvciB7IC8qIEhlYWRlciA0IC0gZm9udCBzcGVjaWZpY2F0aW9ucyBmb3IgYXV0aG9ycyAgKi8KICBmb250LXNpemU6IDIwcHg7CiAgZm9udC1mYW1pbHk6IHN5c3RlbS11aTsKICBjb2xvcjogRGFya1JlZDsKICB0ZXh0LWFsaWduOiBjZW50ZXI7CiAgZm9udC13ZWlnaHQ6IGJvbGQ7Cn0KaDQuZGF0ZSB7IC8qIEhlYWRlciA0IC0gZm9udCBzcGVjaWZpY2F0aW9ucyBmb3IgdGhlIGRhdGUgICovCiAgZm9udC1zaXplOiAxOHB4OwogIGZvbnQtZmFtaWx5OiBzeXN0ZW0tdWk7CiAgY29sb3I6IERhcmtCbHVlOwogIHRleHQtYWxpZ246IGNlbnRlcjsKfQpoMSB7IC8qIEhlYWRlciAxIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBmb3IgbGV2ZWwgMSBzZWN0aW9uIHRpdGxlICAqLwogICAgZm9udC1zaXplOiAyMnB4OwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogbmF2eTsKICAgIHRleHQtYWxpZ246IGNlbnRlcjsKICAgIGZvbnQtd2VpZ2h0OiBib2xkOwp9CmgyIHsgLyogSGVhZGVyIDIgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBsZXZlbCAyIHNlY3Rpb24gdGl0bGUgKi8KICAgIGZvbnQtc2l6ZTogMjBweDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IG5hdnk7CiAgICB0ZXh0LWFsaWduOiBsZWZ0OwogICAgZm9udC13ZWlnaHQ6IGJvbGQ7Cn0KCmgzIHsgLyogSGVhZGVyIDMgLSBmb250IHNwZWNpZmljYXRpb25zIG9mIGxldmVsIDMgc2VjdGlvbiB0aXRsZSAgKi8KICAgIGZvbnQtc2l6ZTogMThweDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IG5hdnk7CiAgICB0ZXh0LWFsaWduOiBsZWZ0OwogICAgZm9udC13ZWlnaHQ6IGJvbGQ7Cn0KCmg0IHsgLyogSGVhZGVyIDQgLSBmb250IHNwZWNpZmljYXRpb25zIG9mIGxldmVsIDQgc2VjdGlvbiB0aXRsZSAgKi8KICAgIGZvbnQtc2l6ZTogMTZweDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IGRhcmtyZWQ7CiAgICB0ZXh0LWFsaWduOiBsZWZ0OwogICAgZm9udC13ZWlnaHQ6IGJvbGQ7Cn0KCmJvZHkgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9CgouaGlnaGxpZ2h0bWUgeyBiYWNrZ3JvdW5kLWNvbG9yOnllbGxvdzsgfQoKcCB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0KCjwvc3R5bGU+CmBgYAoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CiMgY29kZSBjaHVuayBzcGVjaWZpZXMgd2hldGhlciB0aGUgUiBjb2RlLCB3YXJuaW5ncywgYW5kIG91dHB1dCAKIyB3aWxsIGJlIGluY2x1ZGVkIGluIHRoZSBvdXRwdXQgZmlsZXMuCgppZiAoIXJlcXVpcmUoImtuaXRyIikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQogICBsaWJyYXJ5KGtuaXRyKQp9CgppZiAoIXJlcXVpcmUoIk1BU1MiKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJNQVNTIikKICAgbGlicmFyeShNQVNTKQp9CmlmICghcmVxdWlyZSgibGVhZmxldCIpKSB7CiAgIGluc3RhbGwucGFja2FnZXMoImxlYWZsZXQiKQogICBsaWJyYXJ5KGxlYWZsZXQpCn0KCmlmICghcmVxdWlyZSgiZ2dyaWRnZXMiKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJnZ3JpZGdlcyIpCmxpYnJhcnkoZ2dyaWRnZXMpCn0KaWYgKCFyZXF1aXJlKCJ0aWR5dmVyc2UiKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKfQoKaWYgKCFyZXF1aXJlKCJnZ3Bsb3QyIikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpCiAgIGxpYnJhcnkoZ2dwbG90MikKfQppZiAoIXJlcXVpcmUoIm5uZXQiKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJubmV0IikKICAgbGlicmFyeShubmV0KQp9CiAKaWYgKCFyZXF1aXJlKCJub3J0ZXN0IikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygibm9ydGVzdCIpCiAgIGxpYnJhcnkobm9ydGVzdCkKfSAKCmlmICghcmVxdWlyZSgiY29ycnBsb3QiKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJjb3JycGxvdCIpCiAgIGxpYnJhcnkoY29ycnBsb3QpCn0KCmlmICghcmVxdWlyZSgiVklNIikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygiVklNIikKICAgbGlicmFyeShWSU0pCn0KCgppZiAoIXJlcXVpcmUoIm1pY2UiKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJtaWNlIikKICAgbGlicmFyeShtaWNlKQp9CgppZiAoIXJlcXVpcmUoIm5hbmlhciIpKSB7CiAgIGluc3RhbGwucGFja2FnZXMoIm5hbmlhciIpCiAgIGxpYnJhcnkobmFuaWFyKQoKfQoKaWYgKCFyZXF1aXJlKCJHR2FsbHkiKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJHR2FsbHkiKQogICBsaWJyYXJ5KEdHYWxseSkKCn0KCmlmICghcmVxdWlyZSgiZ2xtbmV0IikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygiZ2xtbmV0IikKICAgbGlicmFyeShnbG1uZXQpCgp9CgppZiAoIXJlcXVpcmUoImNhcmV0IikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygiY2FyZXQiKQogICBsaWJyYXJ5KGNhcmV0KQoKfQoKaWYgKCFyZXF1aXJlKCJwUk9DIikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygicFJPQyIpCiAgIGxpYnJhcnkocFJPQykKCn0KCgprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgICAgICAgICAgICAgICAgICAgICBlY2hvID0gVFJVRSwgICAKICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcgPSBGQUxTRSwgIAogICAgICAgICAgICAgICAgICAgICAgcmVzdWx0ID0gVFJVRSwgICAgCiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICBjb21tZW50ID0gTkEKICAgICAgICAgICAgICAgICAgICAgICkgIApgYGAKCgoKIyBJTlRST0RVQ1RJT04KCgpgYGB7cn0KbmhhbmVzIDwtIHJlYWQuY3N2KCJodHRwczovL2ptdXNhMy5naXRodWIuaW8vam11c2EvbmhhbmVzLmNzdiIpCgojQ1JFQVRFIE1JU1NJTkcgVkFMVUVTIGluIHNvbWUgdmFyaWFibGVzCgojIFNldCBzZWVkIGZvciByZXByb2R1Y2liaWxpdHkKc2V0LnNlZWQoMTIzKSAgCgojIERldGVybWluZSB0aGUgbnVtYmVyIG9mIG1pc3NpbmcgdmFsdWVzICgxNSUgb2YgdG90YWwgcm93cykKbnVtX21pc3NpbmcgPC0gcm91bmQoMC4xNCAqIG5yb3cobmhhbmVzKSkKCiMgUmFuZG9tbHkgc2VsZWN0IHJvdyBpbmRpY2VzIHRvIGludHJvZHVjZSBtaXNzaW5nIHZhbHVlcyAKbWlzc2luZ19pbmRpY2VzIDwtIHNhbXBsZSgxOm5yb3cobmhhbmVzKSwgbnVtX21pc3NpbmcsIHJlcGxhY2UgPSBGQUxTRSkKCiMgU2V0IHNlbGVjdGVkIHJvd3MgaW4gYm9keS53ZWlnaHQgdG8gTkEKbmhhbmVzJGJvZHkud2VpZ2h0W21pc3NpbmdfaW5kaWNlc10gPC0gTkEKCiMgVmVyaWZ5IG1pc3NpbmcgdmFsdWVzCiNzdW0oaXMubmEobmhhbmVzJGJvZHkud2VpZ2h0KSkgIAoKCiMgU2V0IHNlZWQgZm9yIHJlcHJvZHVjaWJpbGl0eQpzZXQuc2VlZCg0NTYpICAKCiMgRGV0ZXJtaW5lIHRoZSBudW1iZXIgb2YgbWlzc2luZyB2YWx1ZXMgKDE1JSBvZiB0b3RhbCByb3dzKQpudW1fbWlzc2luZyA8LSByb3VuZCgwLjE1ICogbnJvdyhuaGFuZXMpKQoKIyBSYW5kb21seSBzZWxlY3Qgcm93IGluZGljZXMgdG8gaW50cm9kdWNlIG1pc3NpbmcgdmFsdWVzCm1pc3NpbmdfaW5kaWNlcyA8LSBzYW1wbGUoMTpucm93KG5oYW5lcyksIG51bV9taXNzaW5nLCByZXBsYWNlID0gRkFMU0UpCgojIFNldCBzZWxlY3RlZCByb3dzIGluIGJvZHkud2VpZ2h0IHRvIE5BCm5oYW5lcyRjaG9sZXN0cm9sW21pc3NpbmdfaW5kaWNlc10gPC0gTkEKCgojIFNldCBzZWVkIGZvciByZXByb2R1Y2liaWxpdHkKc2V0LnNlZWQoNzg5KSAgCgojIERldGVybWluZSB0aGUgbnVtYmVyIG9mIG1pc3NpbmcgdmFsdWVzICgxNSUgb2YgdG90YWwgcm93cykKbnVtX21pc3NpbmcgPC0gcm91bmQoMC4xNSAqIG5yb3cobmhhbmVzKSkKCiMgUmFuZG9tbHkgc2VsZWN0IHJvdyBpbmRpY2VzIHRvIGludHJvZHVjZSBtaXNzaW5nIHZhbHVlcwptaXNzaW5nX2luZGljZXMgPC0gc2FtcGxlKDE6bnJvdyhuaGFuZXMpLCBudW1fbWlzc2luZywgcmVwbGFjZSA9IEZBTFNFKQoKIyBTZXQgc2VsZWN0ZWQgcm93cyBpbiByYWNlIHRvIE5BCm5oYW5lcyRyYWNlW21pc3NpbmdfaW5kaWNlc10gPC0gTkEKCiMgVmVyaWZ5IG1pc3NpbmcgdmFsdWVzCgojc3VtKGlzLm5hKG5oYW5lcyRyYWNlKSkgIAojc3VtKGlzLm5hKG5oYW5lcyRjaG9sZXN0cm9sKSkgCiNzdW0oaXMubmEobmhhbmVzJGJvZHkud2VpZ2h0KSkgCgojIGNyZWF0ZSBhIGNvcHkgb2YgbmhhbmVzIGZvciBNSUNFCm5oYW5lczEgPC0gbmhhbmVzCm5oYW5lczEkcmFjZSA8LSBhcy5mYWN0b3IobmhhbmVzMSRyYWNlKQpuaGFuZXMxJGNob2xlc3Ryb2wgPC0gYXMubnVtZXJpYyhuaGFuZXMxJGNob2xlc3Ryb2wpCgoKCmBgYAoKClRoZSBOYXRpb25hbCBIZWFsdGggYW5kIE51dHJpdGlvbiBFeGFtaW5hdGlvbiBTdXJ2ZXkgKE5IQU5FUykgaXMgYSBwcm9ncmFtIGNvbmR1Y3RlZCBieSB0aGUgTmF0aW9uYWwgQ2VudGVyIGZvciBIZWFsdGggU3RhdGlzdGljcyAoTkNIUyksIGEgZGl2aXNpb24gb2YgdGhlIENlbnRlcnMgZm9yIERpc2Vhc2UgQ29udHJvbCBhbmQgUHJldmVudGlvbiAoQ0RDKS4gTkhBTkVTIGhhcyBiZWVuIGNvbmR1Y3RlZCBpbiB2YXJpb3VzIGZvcm1zIHNpbmNlIHRoZSBlYXJseSAxOTYwcywgd2l0aCB0aGUgY3VycmVudCBjb250aW51b3VzIHN1cnZleSBmb3JtYXQgYmVnaW5uaW5nIGluIDE5OTkuIFRoZSBzdXJ2ZXkgaXMgZGVzaWduZWQgdG8gYXNzZXNzIHRoZSBoZWFsdGggYW5kIG51dHJpdGlvbmFsIHN0YXR1cyBvZiBhZHVsdHMgYW5kIGNoaWxkcmVuIGluIHRoZSBVbml0ZWQgU3RhdGVzIHRocm91Z2ggYSBjb21iaW5hdGlvbiBvZiBpbnRlcnZpZXdzLCBwaHlzaWNhbCBleGFtaW5hdGlvbnMsIGFuZCBsYWJvcmF0b3J5IHRlc3RzLiBEYXRhIGlzIGNvbGxlY3RlZCBmcm9tIGEgbmF0aW9uYWxseSByZXByZXNlbnRhdGl2ZSBzYW1wbGUgb2YgdGhlIFUuUy4gcG9wdWxhdGlvbiB1c2luZyBhIGNvbXBsZXgsIG11bHRpc3RhZ2UgcHJvYmFiaWxpdHkgc2FtcGxpbmcgZGVzaWduLiBQYXJ0aWNpcGFudHMgdW5kZXJnbyBob3VzZWhvbGQgaW50ZXJ2aWV3cyBmb2xsb3dlZCBieSBoZWFsdGggZXhhbWluYXRpb25zIGF0IG1vYmlsZSBleGFtaW5hdGlvbiBjZW50ZXJzIChNRUNzKSwgd2hlcmUgdHJhaW5lZCBtZWRpY2FsIHByb2Zlc3Npb25hbHMgY29sbGVjdCBiaW9sb2dpY2FsIHNhbXBsZXMgYW5kIGNvbmR1Y3QgY2xpbmljYWwgYXNzZXNzbWVudHMuIFRoZSBOSEFORVMgZGF0YSBwcm92aWRlcyBjcml0aWNhbCBpbnNpZ2h0cyBpbnRvIHB1YmxpYyBoZWFsdGggdHJlbmRzLCBoZWxwaW5nIHBvbGljeW1ha2VycywgcmVzZWFyY2hlcnMsIGFuZCBoZWFsdGhjYXJlIHByb2Zlc3Npb25hbHMgbWFrZSBpbmZvcm1lZCBkZWNpc2lvbnMgb24gbmF0aW9uYWwgaGVhbHRoIHByaW9yaXRpZXMuIFRoZSBwdXJwb3NlIG9mIHRoaXMgc3R1ZHkgaXMgdG8gYXNzZXNzIHRoZSBoZWFsdGggYW5kIG51dHJpdGlvbmFsIHN0YXR1cyBvZiB0aGUgc3R1ZHkgcGFydGljaXBhbnRzIHdpdGggbWV0cmljcyBzdWNoIGFzIGhpZ2ggYmxvb2QgcHJlc3N1cmUuIAoKVGhlcmUgYXJlIDE1IGZlYXR1cmVzIGFuZCA3OTI3IG9ic2VydmF0aW9ucyBpbiB0aGlzIGRhdGEgc2V0LiBUaGVzZSBmZWF0dXJlcyBhcmUgbGlzdGVkIGJlbG93LgoKMSkgb2JzOiBSZXNwb25kZW50IElkZW50aWZpY2F0aW9uIE51bWJlcgoyKSBwc3U6IFBzZXVkby1QU1UgMSwyIHBzdQozKSBzdHJhdHVtOiBQc2V1ZG8tc3RyYXR1bSAoMDEgLSA0OSkKNCkgc3RhdC53ZWlnaHQ6IFN0YXRpc3RpY2FsIHdlaWdodCAoMjI1LjkzIC0gMTM5NzQ0LjkpCjUpIGFnZTogQWdlICh5ZWFycykgCjYpIHNleDogMCA9IEZlbWFsZSwgMSA9IE1hbGUgc2V4CjcpIHJhY2U6IFJhY2UgKDEgPSBXaGl0ZTsgMiA9IEJsYWNrOyAzID0gT3RoZXIpCjgpIGJvZHkud2VpZ2h0OiBCb2R5IFdlaWdodCAocG91bmRzKQo5KSBoZWlnaHQ6IFN0YW5kaW5nIEhlaWdodCAoaW5jaGVzKQoxMCkgYXZnLnNicDogQXZlcmFnZSBTeXN0b2xpYyBCUCAobW0vSGcpIAoxMSkgYXZnLmRicDogQXZlcmFnZSBEaWFzdG9saWMgQlAgKG1tL0hnKSAKMTIpIHBhc3Quc21rOiBIYXMgcmVzcG9uZGVudCBzbW9rZWQgPiAxMDAgY2lnYXJldHRlcyBpbiBsaWZlICgxID0gWWVzLCAyID0gTm8pCjEzKSBjdXJyZW50LnNtazogRG9lcyByZXNwb25kZW50IHNtb2tlIGNpZ2FyZXR0ZXMgbm93PyAoMSA9IFllcywgMiA9IE5vKQoxNCkgY2hvbGVzdHJvbDogU2VydW0gQ2hvbGVzdGVyb2wgKG1nLzEwMG1sKSAKMTUpIGhicDogSGlnaCBCbG9vZCBQcmVzc3VyZSAoMCBpZiBQRVBNTksxUiA8PSAxNDA7IDEgaWYgUEVQTU5LMVIgPiAxNDApCgpUaGUgb2JzLCBwc3UsIHN0cmF0dW0sIGFuZCBzdGF0LndlaWdodCB2YXJpYWJsZXMgYXJlIG5vdCBpbmNsdWRlZCBpbiB0aGlzIGFuYWx5c2lzIGJlY2F1c2UgdGhleSBkbyBub3QgZGlyZWN0bHkgcHJvdmlkZSBoZWFsdGgtcmVsYXRlZCBpbmZvcm1hdGlvbi4gCgpUaGUgZGF0YSBzZXQgaGFzIDMxNyBtaXNzaW5nIHZhbHVlcyBmb3IgYm9keSB3ZWlnaHQgYW5kIDM5NiBtaXNzaW5nIHZhbHVlcyBmb3IgY2hvbGVzdGVyb2wuIAoKIyBFREEKCgojIyBEaXN0cmlidXRpb24gb2YgSW5kaXZpZHVhbCBGZWF0dXJlcwoKVGhlIGRpc3RyaWJ1dGlvbnMgb2YgdGhlIGluZGl2aWR1YWwgZmVhdHVyZXMgaW4gdGhlIE5IQU5FUyBkYXRhc2V0IHByb3ZpZGUgYSBzbmFwc2hvdCBvZiB0aGUgY2hhcmFjdGVyaXN0aWNzIG9mIHRoZSBwb3B1bGF0aW9uIGluIHRlcm1zIG9mIHZhcmlvdXMgaGVhbHRoIGFuZCBkZW1vZ3JhcGhpYyB2YXJpYWJsZXMuIFVuZGVyc3RhbmRpbmcgdGhlc2UgZGlzdHJpYnV0aW9ucyBpcyBlc3NlbnRpYWwgZm9yIGlkZW50aWZ5aW5nIHBhdHRlcm5zLCBkZXRlY3RpbmcgcG90ZW50aWFsIGJpYXNlcywgYW5kIGFzc2Vzc2luZyB0aGUgcmFuZ2UgYW5kIHZhcmlhYmlsaXR5IG9mIGVhY2ggZmVhdHVyZS4gVGhpcyBhbmFseXNpcyBoZWxwcyBpbiB1bmRlcnN0YW5kaW5nIGhvdyB2YXJpYWJsZXMgc3VjaCBhcyBhZ2UsIGJvZHkgd2VpZ2h0LCBibG9vZCBwcmVzc3VyZSwgYW5kIGxpZmVzdHlsZSBmYWN0b3JzIGFyZSBzcHJlYWQgYWNyb3NzIHRoZSBkYXRhc2V0LCB3aGljaCBpcyBjcnVjaWFsIGZvciBzdWJzZXF1ZW50IHN0YXRpc3RpY2FsIG1vZGVsaW5nIGFuZCBpbnRlcnByZXRhdGlvbi4KCmBgYHtyfQoKIyBDb252ZXJ0IHZhcmlhYmxlcyB0byBmYWN0b3JzIHdpdGggcHJvcGVyIGxhYmVscwpuaGFuZXMkc2V4IDwtIGZhY3RvcihuaGFuZXMkc2V4LCBsZXZlbHMgPSBjKDAsIDEpLCBsYWJlbHMgPSBjKCJGZW1hbGUiLCAiTWFsZSIpKQpuaGFuZXMkcmFjZSA8LSBmYWN0b3IobmhhbmVzJHJhY2UsIGxldmVscyA9IGMoMSwgMiwgMyksIGxhYmVscyA9IGMoIldoaXRlIiwgIkJsYWNrIiwgIk90aGVyIikpCm5oYW5lcyRwYXN0LnNtayA8LSBmYWN0b3IobmhhbmVzJHBhc3Quc21rLCBsZXZlbHMgPSBjKDEsIDIpLCBsYWJlbHMgPSBjKCJZZXMiLCAiTm8iKSkKbmhhbmVzJGN1cnJlbnQuc21rIDwtIGZhY3RvcihuaGFuZXMkY3VycmVudC5zbWssIGxldmVscyA9IGMoMSwgMiksIGxhYmVscyA9IGMoIlllcyIsICJObyIpKQoKIyBDcmVhdGUgZnJlcXVlbmN5IHRhYmxlcwpzZXhfY291bnQgPC0gdGFibGUobmhhbmVzJHNleCkKCnJhY2VfY291bnQgPC0gdGFibGUobmhhbmVzJHJhY2UpCgpwYXN0LnNta19jb3VudCA8LSB0YWJsZShuaGFuZXMkcGFzdC5zbWspCgpjdXJyZW50LnNta19jb3VudCA8LSB0YWJsZShuaGFuZXMkY3VycmVudC5zbWspCgoKcGFyKG1mcm93ID0gYygyLCAyKSkKCiMgUGxvdCB0aGUgYmFyIGNoYXJ0cwpiYXJwbG90KGhlaWdodCA9IHNleF9jb3VudCwgY29sID0gInN0ZWVsYmx1ZSIsIG1haW4gPSAiU2V4IiwgeGxhYiA9ICJTZXgiLCB5bGFiID0gIkNvdW50IikKCmJhcnBsb3QoaGVpZ2h0ID0gcmFjZV9jb3VudCwgY29sID0gInN0ZWVsYmx1ZSIsIG1haW4gPSAiUmFjZSIsIHhsYWIgPSAiUmFjZSIsIHlsYWIgPSAiQ291bnQiKQoKYmFycGxvdChoZWlnaHQgPSBwYXN0LnNta19jb3VudCwgY29sID0gInN0ZWVsYmx1ZSIsIG1haW4gPSAiUGFzdCBTbW9rZXIiLCB4bGFiID0gIlBhc3QgU21va2VyIiwgeWxhYiA9ICJDb3VudCIpCgpiYXJwbG90KGhlaWdodCA9IGN1cnJlbnQuc21rX2NvdW50LCBjb2wgPSAic3RlZWxibHVlIiwgbWFpbiA9ICJDdXJyZW50IFNtb2tlciIsIHhsYWIgPSAiQ3VycmVudCBTbW9rZXIiLCB5bGFiID0gIkNvdW50IikKCmBgYAoKVGhlcmUgYXJlIHNsaWdodGx5IG1vcmUgbWFsZSBvYnNlcnZhdGlvbnMgdGhhbiBmZW1hbGUgb2JzZXJ2YXRpb24gaW4gdGhpcyBkYXRhIHNldC4gVGhlIG1ham9yaXR5IG9mIHBhcnRpY2lwYW50cyBhcmUgd2hpdGUsIGZvbGxvd2VkIGJ5IGJsYWNrLiBBbGwgcGFydGljaXBhbnRzIGFyZSByZWNvcmRlZCBhcyBiZWluZyBwYXN0IHNtb2tlcnMsIHdoaWNoIGlzIGxpa2VseSBhbiBlcnJvci4gVGhlcmUgaXMgYW4gaW1iYWxhbmNlIGZvciBwYXN0IHNtb2tlci4gSW4gdHVybiwgcGFzdCBzbW9rZXIgY2Fubm90IGJlIHVzZWQgZm9yIGFuYWx5c2lzLiBBYm91dCBoYWxmIG9mIGN1cnJlbnQgcGFydGljaXBhbnRzIGFyZSBjdXJyZW50IHNtb2tlcnMuIAoKYGBge3J9CgpwYXIobWZyb3cgPSBjKDIsIDIpKSAgCgojIEhpc3RvZ3JhbSBmb3IgQ2hvbGVzdGVyb2wKaGlzdChuaGFuZXMkY2hvbGVzdHJvbCwgCiAgICAgbWFpbiA9ICJIaXN0b2dyYW0gb2YgQ2hvbGVzdGVyb2wiLCAKICAgICB4bGFiID0gIkNob2xlc3Rlcm9sIiwgCiAgICAgY29sID0gInN0ZWVsYmx1ZSIsIAogICAgIGJvcmRlciA9ICJibGFjayIsIAogICAgIGJyZWFrcyA9IDIwKSAgIyBDb250cm9sIG51bWJlciBvZiBiaW5zCiAgICAKICAgICAKIyBIaXN0b2dyYW0gZm9yIFN5c3RvbGljIEJQCmhpc3QobmhhbmVzJGF2Zy5zYnAsIAogICAgIG1haW4gPSAiSGlzdG9ncmFtIG9mIFN5c3RvbGljIEJQIiwgCiAgICAgeGxhYiA9ICJTeXN0b2xpYyBCUCIsIAogICAgIGNvbCA9ICJzdGVlbGJsdWUiLCAKICAgICBib3JkZXIgPSAiYmxhY2siLCAKICAgICBicmVha3MgPSAyMCkKICAgIAoKIyBIaXN0b2dyYW0gZm9yIEJvZHkgV2VpZ2h0Cmhpc3QobmhhbmVzJGJvZHkud2VpZ2h0LCAKICAgICBtYWluID0gIkhpc3RvZ3JhbSBvZiBCb2R5IFdlaWdodCIsIAogICAgIHhsYWIgPSAiQm9keSBXZWlnaHQiLCAKICAgICBjb2wgPSAic3RlZWxibHVlIiwgCiAgICAgYm9yZGVyID0gImJsYWNrIiwgCiAgICAgYnJlYWtzID0gMjApCiAgCiAgICAgCiMgSGlzdG9ncmFtIGZvciBIZWlnaHQKaGlzdChuaGFuZXMkYm9keS53ZWlnaHQsIAogICAgIG1haW4gPSAiSGlzdG9ncmFtIG9mIEhlaWdodCIsIAogICAgIHhsYWIgPSAiSGVpZ2h0IiwgCiAgICAgY29sID0gInN0ZWVsYmx1ZSIsIAogICAgIGJvcmRlciA9ICJibGFjayIsIAogICAgIGJyZWFrcyA9IDIwKSAgIAogICAgIApgYGAKCk1vc3QgcGFydGljaXBhbnRzIGRvIG5vdCBoYXZlIGhpZ2ggYmxvb2QgcHJlc3N1cmUuIFRoZSBhZ2Ugb2YgcGFydGljaXBhbnRzIHZhcmllcyBmcm9tIGFib3V0IDIwIHRvIGFib3V0IDkwLiBUaGUgaGVpZ2h0IGRpc3RyaWJ1dGlvbiBpcyByb3VnaGx5IHN5bW1ldHJpYy4gVGhlIGJvZHkgd2VpZ2h0IGRpc3RyaWJ1dGlvbiBpcyBza2V3ZWQgcmlnaHQgZHVlIHRvIHNvbWUgaGlnaCBvdXRsaWVycy4gVGhlIGhpZ2ggb3V0bGllcnMgbWF5IGluZGljYXRlIG9iZXNpdHkuIAoKCgpgYGB7cn0KCnBhcihtZnJvdyA9IGMoMiwyKSkKCmhpc3QobmhhbmVzJGF2Zy5zYnAsIGNvbCA9ICJzdGVlbGJsdWUiLCAKICAgICBtYWluID0gIlN5c3RvbGljIEJQIiwKICAgICB4bGFiID0gIlN5c3RvbGljIEJQIiwgeWxhYiA9ICJGcmVxdWVuY3kiLAogICAgIGJyZWFrcyA9IDMwKQoKaGlzdChuaGFuZXMkYXZnLmRicCwgY29sID0gInN0ZWVsYmx1ZSIsIAogICAgIG1haW4gPSAiRGlhc3RvbGljIEJQIiwKICAgICB4bGFiID0gIkRpYXN0b2xpYyBCUCIsIHlsYWIgPSAiRnJlcXVlbmN5IiwKICAgICBicmVha3MgPSAzMCkKCmhpc3QobmhhbmVzJGNob2xlc3Ryb2wsIGNvbCA9ICJzdGVlbGJsdWUiLCAKICAgICBtYWluID0gIkNob2xlc3Rlcm9sIiwKICAgICB4bGFiID0gIkNob2xlc3Rlcm9sIiwgeWxhYiA9ICJGcmVxdWVuY3kiLAogICAgIGJyZWFrcyA9IDMwKQoKCmBgYAoKU3lzdG9saWMgQlAgYW5kIGNob2xlc3Rlcm9sIGhhdmUgc2tld2VkIHJpZ2h0IGRpc3RyaWJ1dGlvbnMuIERpYXN0b2xpYyBCUCBpcyByb3VnaGx5IHN5bW1ldHJpYy4gT2YgdGhlIDc5MjcgcGFydGljaXBhbnRzLCAxOTY0IGFyZSBvYmVzZS4gCgoKIyMgUmVsYXRpb25zaGlwIGJldHdlZW4gRmVhdHVyZXMKCkV4YW1pbmluZyByZWxhdGlvbnNoaXBzIGJldHdlZW4gdmFyaWFibGVzIHVzaW5nIHNjYXR0ZXJwbG90cyBhbmQgYSBjb3JyZWxhdGlvbiBtYXRyaXggcHJvdmlkZXMgYSBjb21wcmVoZW5zaXZlIGFwcHJvYWNoIHRvIHVuZGVyc3RhbmRpbmcgYXNzb2NpYXRpb25zLiBTY2F0dGVycGxvdHMgdmlzdWFsbHkgcmV2ZWFsIGhvdyB0d28gY29udGludW91cyB2YXJpYWJsZXMgaW50ZXJhY3QsIGFsbG93aW5nIHVzIHRvIGlkZW50aWZ5IHRyZW5kcywgY29ycmVsYXRpb25zLCBhbmQgcG90ZW50aWFsIG91dGxpZXJzLiBNZWFud2hpbGUsIGEgY29ycmVsYXRpb24gbWF0cml4IHF1YW50aWZpZXMgdGhlIHN0cmVuZ3RoIGFuZCBkaXJlY3Rpb24gb2YgcmVsYXRpb25zaGlwcyBiZXR3ZWVuIG11bHRpcGxlIHZhcmlhYmxlcyBhdCBvbmNlLCBoZWxwaW5nIHRvIHBpbnBvaW50IHdoaWNoIHBhaXJzIGFyZSBzdHJvbmdseSBjb3JyZWxhdGVkLiBUb2dldGhlciwgc2NhdHRlcnBsb3RzIGFuZCBhIGNvcnJlbGF0aW9uIG1hdHJpeCBvZmZlciB2YWx1YWJsZSBpbnNpZ2h0cyBpbnRvIHRoZSB1bmRlcmx5aW5nIHBhdHRlcm5zIGluIHRoZSBkYXRhLCBndWlkaW5nIGZ1cnRoZXIgc3RhdGlzdGljYWwgYW5hbHlzaXMgYW5kIG1vZGVsIHNlbGVjdGlvbi4KCmBgYHtyfQojIFNldCBzZWVkIGZvciByZXByb2R1Y2liaWxpdHkKc2V0LnNlZWQoMTIzKQoKIyBTYW1wbGUgNTAwIHJvd3MgKGFkanVzdCB0aGUgbnVtYmVyIGFzIG5lZWRlZCkKc2FtcGxlX2luZGljZXMgPC0gc2FtcGxlKG5yb3cobmhhbmVzKSwgc2l6ZSA9IDUwMCwgcmVwbGFjZSA9IFRSVUUpCnNhbXBsZWRfZGF0YSA8LSBuaGFuZXNbc2FtcGxlX2luZGljZXMsIGMoImFnZSIsICJib2R5LndlaWdodCIsICJoZWlnaHQiLCAiYXZnLnNicCIsICJhdmcuZGJwIiwgImNob2xlc3Ryb2wiKV0KCiMgQ3JlYXRlIGEgcGFpcndpc2Ugc2NhdHRlcnBsb3QgbWF0cml4IHdpdGggdGhlIHNhbXBsZWQgZGF0YQpwYWlycyhzYW1wbGVkX2RhdGEsIAogICAgICBtYWluID0gIlBhaXJ3aXNlIFNjYXR0ZXJwbG90cyAoQm9vdHN0cmFwcGVkIFNhbXBsZSkiLAogICAgICBwY2ggPSAxOSwgICAgICAgICAgICMgU2hhcGUgb2YgdGhlIHBvaW50cyAoY2lyY2xlKQogICAgICBjb2wgPSByZ2IoMCwgMCwgMSwgMC41KSAgIyBDb2xvciB3aXRoIHRyYW5zcGFyZW5jeSAoYmx1ZSkKKQoKYGBgCgoKCmBgYHtyfQoKbmhhbmVzX3N1YnNldCA8LSBuaGFuZXNbLCBjKCJhZ2UiLCAiYm9keS53ZWlnaHQiLCAiaGVpZ2h0IiwgImF2Zy5zYnAiLCAiYXZnLmRicCIsICJjaG9sZXN0cm9sIildCgojIENvbXB1dGUgdGhlIGNvcnJlbGF0aW9uIG1hdHJpeApjb3JfbWF0cml4IDwtIGNvcihuaGFuZXNfc3Vic2V0LCB1c2UgPSAicGFpcndpc2UuY29tcGxldGUub2JzIikKCiMgUHJpbnQgdGhlIGNvcnJlbGF0aW9uIG1hdHJpeApwcmludChjb3JfbWF0cml4KQoKY29ycnBsb3QoY29yX21hdHJpeCwgbWV0aG9kID0gImNvbG9yIiwgdHlwZSA9ICJ1cHBlciIsIHRsLmNvbCA9ICJibGFjayIsIHRsLmNleCA9IDAuOCkKCgpgYGAKClRoZSBtb3N0IGhpZ2hseSBjb3JyZWxhdGUgZmVhdHVyZXMgYXJlIGFnZSBhbmQgYXZlcmFnZSBzeXN0b2xpYyBibG9vZCBwcmVzc3VyZSwgYm9keSB3ZWlnaHQgYW5kIGhlaWdodCwgYXZlcmFnZSBzeXN0b2xpYyBibG9vZCBwcmVzc3VyZSBhbmQgYXZlcmFnZSBkaWFzdG9saWMgYmxvb2QgcHJlc3N1cmUsIGFnZSBhbmQgY2hvbGVzdGVyb2wsIGJvZHkgd2VpZ2h0IGFuZCBjaG9sZXN0ZXJvbCwgYW5kIGJvZHkgd2VpZ2ggYW5kIGF2ZXJhZ2UgZGlhc3RvbGljIGJsb29kIHByZXNzdXJlLiBUaGUgcGFpcndpc2UgcmVsYXRpb25zaGlwcyBhcmUgZGlzcGxheWVkIHdpdGggaW5kaXZpZHVhbCBzY2F0dGVyIHBsb3RzLiAKCmBgYHtyfQojIFNldCBzZWVkIGZvciByZXByb2R1Y2liaWxpdHkKc2V0LnNlZWQoMTIzKQoKIyBCb290c3RyYXAgYSBzbWFsbGVyIHNhbXBsZSAoYWRqdXN0IHNpemUgYXMgbmVlZGVkKQpzYW1wbGVfaW5kaWNlcyA8LSBzYW1wbGUobnJvdyhuaGFuZXMpLCBzaXplID0gNTAwLCByZXBsYWNlID0gVFJVRSkKc2FtcGxlZF9kYXRhIDwtIG5oYW5lc1tzYW1wbGVfaW5kaWNlcywgXQoKIyBTZXQgdXAgYSAyeDMgcGxvdHRpbmcgZ3JpZApwYXIobWZyb3cgPSBjKDIsIDMpKQoKIyBTY2F0dGVycGxvdCBmb3IgQWdlIGFuZCBBdmcuIFN5c3RvbGljIEJsb29kIFByZXNzdXJlCnBsb3Qoc2FtcGxlZF9kYXRhJGFnZSwgc2FtcGxlZF9kYXRhJGF2Zy5zYnAsIG1haW4gPSAiQWdlIHZzIEF2Zy4gU3lzdG9saWMgQlAiLCAKICAgICB4bGFiID0gIkFnZSIsIHlsYWIgPSAiQXZnLiBTeXN0b2xpYyBCUCIsIGNvbCA9ICJibHVlIiwgcGNoID0gMTkpCgojIFNjYXR0ZXJwbG90IGZvciBCb2R5IFdlaWdodCBhbmQgSGVpZ2h0CnBsb3Qoc2FtcGxlZF9kYXRhJGJvZHkud2VpZ2h0LCBzYW1wbGVkX2RhdGEkaGVpZ2h0LCBtYWluID0gIkJvZHkgV2VpZ2h0IHZzIEhlaWdodCIsIAogICAgIHhsYWIgPSAiQm9keSBXZWlnaHQiLCB5bGFiID0gIkhlaWdodCIsIGNvbCA9ICJyZWQiLCBwY2ggPSAxOSkKCiMgU2NhdHRlcnBsb3QgZm9yIEF2Zy4gU3lzdG9saWMgQmxvb2QgUHJlc3N1cmUgYW5kIEF2Zy4gRGlhc3RvbGljIEJsb29kIFByZXNzdXJlCnBsb3Qoc2FtcGxlZF9kYXRhJGF2Zy5zYnAsIHNhbXBsZWRfZGF0YSRhdmcuZGJwLCBtYWluID0gIkF2Zy4gU3lzdG9saWMgdnMgQXZnLiBEaWFzdG9saWMgQlAiLCAKICAgICB4bGFiID0gIkF2Zy4gU3lzdG9saWMgQlAiLCB5bGFiID0gIkF2Zy4gRGlhc3RvbGljIEJQIiwgY29sID0gImZvcmVzdGdyZWVuIiwgcGNoID0gMTkpCgojIFNjYXR0ZXJwbG90IGZvciBBZ2UgYW5kIENob2xlc3Rlcm9sCnBsb3Qoc2FtcGxlZF9kYXRhJGFnZSwgc2FtcGxlZF9kYXRhJGNob2xlc3Ryb2wsIG1haW4gPSAiQWdlIHZzIENob2xlc3Rlcm9sIiwgCiAgICAgeGxhYiA9ICJBZ2UiLCB5bGFiID0gIkNob2xlc3Rlcm9sIiwgY29sID0gInB1cnBsZSIsIHBjaCA9IDE5KQoKIyBTY2F0dGVycGxvdCBmb3IgQXZnLiBTeXN0b2xpYyBCUCBhbmQgQ2hvbGVzdGVyb2wKcGxvdChzYW1wbGVkX2RhdGEkYXZnLnNicCwgc2FtcGxlZF9kYXRhJGNob2xlc3Ryb2wsIG1haW4gPSAiQXZnIFN5c3RvbGljIEJQIHZzIENob2xlc3Rlcm9sIiwgCiAgICAgeGxhYiA9ICJDaG9sZXN0ZXJvbCIsIHlsYWIgPSAiQXZnLlNCUCIsIGNvbCA9ICJnb2xkIiwgcGNoID0gMTkpCgojIFNjYXR0ZXJwbG90IGZvciBCb2R5IFdlaWdodCBhbmQgQXZnLiBEaWFzdG9saWMgQmxvb2QgUHJlc3N1cmUKcGxvdChzYW1wbGVkX2RhdGEkYm9keS53ZWlnaHQsIHNhbXBsZWRfZGF0YSRhdmcuZGJwLCBtYWluID0gIkJvZHkgV2VpZ2h0IHZzIEF2Zy4gRGlhc3RvbGljIEJQIiwgCiAgICAgeGxhYiA9ICJCb2R5IFdlaWdodCIsIHlsYWIgPSAiQXZnLiBEaWFzdG9saWMgQlAiLCBjb2wgPSAibWFyb29uIiwgcGNoID0gMTkpCmBgYAoKU2l4IG9mIHRoZSBtb3N0IGNvcnJlbGF0ZWQgcGFpcndpc2UgcmVsYXRpb25zaGlwIGFyZSB2aXN1YWxpemVkIGluIHNjYXR0ZXIgcGxvdHMuIEFsbCBwYWlyd2lzZSByZWxhdGlvbnNoaXBzIGFyZSBsaW5lYXIgd2l0aCBubyBhcHBhcmVudCBjbHVzdGVyaW5nLiAKCgpgYGB7cn0KCiMgU2V0IHVwIGEgMngyIHBsb3R0aW5nIGdyaWQKcGFyKG1mcm93ID0gYygyLCAyKSkKCiMgQ3JlYXRlIGEgY29udGluZ2VuY3kgdGFibGUKc2V4X2hicF90YWJsZSA8LSB0YWJsZShuaGFuZXMkc2V4LCBuaGFuZXMkaGJwKQoKIyBHZW5lcmF0ZSBtb3NhaWMgcGxvdAptb3NhaWNwbG90KHNleF9oYnBfdGFibGUsIAogICAgICAgICAgIGNvbCA9IGMoImdvbGQiLCAicm95YWxibHVlIiksIAogICAgICAgICAgIG1haW4gPSAiU2V4IGFuZCBIaWdoIEJsb29kIFByZXNzdXJlIiwKICAgICAgICAgICB4bGFiID0gIlNleCBTdGF0dXMiLCAKICAgICAgICAgICB5bGFiID0gIkhCUCBTdGF0dXMiLAogICAgICAgICAgIGJvcmRlciA9ICJibGFjayIpCgoKIyBDcmVhdGUgYSBjb250aW5nZW5jeSB0YWJsZQpyYWNlX2hicF90YWJsZSA8LSB0YWJsZShuaGFuZXMkcmFjZSwgbmhhbmVzJGhicCkKCiMgR2VuZXJhdGUgbW9zYWljIHBsb3QKbW9zYWljcGxvdChyYWNlX2hicF90YWJsZSwgCiAgICAgICAgICAgY29sID0gYygiZ29sZCIsICJyb3lhbGJsdWUiKSwgCiAgICAgICAgICAgbWFpbiA9ICJSYWNlIGFuZCBIaWdoIEJsb29kIFByZXNzdXJlIiwKICAgICAgICAgICB4bGFiID0gIlJhY2UiLCAKICAgICAgICAgICB5bGFiID0gIkhCUCBTdGF0dXMiLAogICAgICAgICAgIGJvcmRlciA9ICJibGFjayIpCgoKIyBDcmVhdGUgYSBjb250aW5nZW5jeSB0YWJsZQpjdXJyZW50LnNta19oYnBfdGFibGUgPC0gdGFibGUobmhhbmVzJGN1cnJlbnQuc21rLCBuaGFuZXMkaGJwKQoKIyBHZW5lcmF0ZSBtb3NhaWMgcGxvdAptb3NhaWNwbG90KGN1cnJlbnQuc21rX2hicF90YWJsZSwgCiAgICAgICAgICAgY29sID0gYygiZ29sZCIsICJyb3lhbGJsdWUiKSwgCiAgICAgICAgICAgbWFpbiA9ICJDdXJyZW50IFNtb2tpbmcgU3RhdHVzIGFuZCBIQlAiLAogICAgICAgICAgIHhsYWIgPSAiQ3VycmVudCBTbW9raW5nIFN0YXR1cyIsIAogICAgICAgICAgIHlsYWIgPSAiSEJQIFN0YXR1cyIsCiAgICAgICAgICAgYm9yZGVyID0gImJsYWNrIikKCgojIENyZWF0ZSBhIGNvbnRpbmdlbmN5IHRhYmxlCnBhc3Quc21rX2hicF90YWJsZSA8LSB0YWJsZShuaGFuZXMkcGFzdC5zbWssIG5oYW5lcyRoYnApCgojIEdlbmVyYXRlIG1vc2FpYyBwbG90Cm1vc2FpY3Bsb3QocGFzdC5zbWtfaGJwX3RhYmxlLCAKICAgICAgICAgICBjb2wgPSBjKCJnb2xkIiwgInJveWFsYmx1ZSIpLCAKICAgICAgICAgICBtYWluID0gIlBhc3QgU21va2luZyBTdGF0dXMgYW5kIEhCUCIsCiAgICAgICAgICAgeGxhYiA9ICJQYXN0IFNtb2tpbmcgU3RhdHVzIiwgCiAgICAgICAgICAgeWxhYiA9ICJIQlAgU3RhdHVzIiwKICAgICAgICAgICBib3JkZXIgPSAiYmxhY2siKQpgYGAKClJlbGF0aW9uc2hpcCBiZXR3ZWVuIGhpZ2ggYmxvb2QgcHJlc3N1cmUgYW5kIHJhY2UsIHNleCwgYW5kIGN1cnJlbnQgc21va2luZyBzdGF0dXMgY2FuIGJlIHZpc3VhbGl6ZWQgaW4gdGhlIG1vc2FpYyBwbG90cy4gVGhlcmUgYXBwZWFycyB0byBiZSBhbiBhc3NvY2lhdGlvbiBiZXR3ZWVuIGhpZ2ggY3VycmVudCBzbW9raW5nIGFuZCByYWNlIHdpdGggaGlnaCBibG9vZCBwcmVzc3VyZS4gQSBsZXNzIHByb25vdW5jZWQgcmVsYXRpb25zaGlwIGNhbiBiZWVuIHNlZW4gYmV0d2VlbiBzZXggYW5kIHJhY2Ugd2l0aCBoaWdoIGJsb29kIHByZXNzdXJlLiAKCgpgYGB7cn0KCiMgU2V0IHVwIGEgMngyIHBsb3R0aW5nIGdyaWQKcGFyKG1mcm93ID0gYygxLCAyKSkKCgojIENyZWF0ZSBhIGNvbnRpbmdlbmN5IHRhYmxlCmN1cnJlbnQuc21rX3JhY2VfdGFibGUgPC0gdGFibGUobmhhbmVzJHJhY2UsIG5oYW5lcyRjdXJyZW50LnNtaykKCiMgR2VuZXJhdGUgbW9zYWljIHBsb3QKbW9zYWljcGxvdChjdXJyZW50LnNta19yYWNlX3RhYmxlLCAKICAgICAgICAgICBjb2wgPSBjKCJnb2xkIiwgInJveWFsYmx1ZSIpLCAKICAgICAgICAgICBtYWluID0gIlJhY2UgYW5kIEN1cnJlbnQgU21va2UgU3RhdHVzIiwKICAgICAgICAgICB4bGFiID0gIlJhY2UiLCAKICAgICAgICAgICB5bGFiID0gIkN1cnJlbnQgU21va2UiLAogICAgICAgICAgIGJvcmRlciA9ICJibGFjayIpCgoKIyBDcmVhdGUgYSBjb250aW5nZW5jeSB0YWJsZQpjdXJyZW50LnNta19zZXhfdGFibGUgPC0gdGFibGUobmhhbmVzJHNleCwgbmhhbmVzJGN1cnJlbnQuc21rKQoKIyBHZW5lcmF0ZSBtb3NhaWMgcGxvdAptb3NhaWNwbG90KGN1cnJlbnQuc21rX3NleF90YWJsZSwgCiAgICAgICAgICAgY29sID0gYygiZ29sZCIsICJyb3lhbGJsdWUiKSwgCiAgICAgICAgICAgbWFpbiA9ICJTZXggYW5kIEN1cnJlbnQgU21va2UgU3RhdHVzIiwKICAgICAgICAgICB4bGFiID0gIlNleCIsIAogICAgICAgICAgIHlsYWIgPSAiQ3VycmVudCBTbW9rZSIsCiAgICAgICAgICAgYm9yZGVyID0gImJsYWNrIikKCiMgQ3JlYXRlIGEgY29udGluZ2VuY3kgdGFibGUKcGFzdC5zbWtfcmFjZV90YWJsZSA8LSB0YWJsZShuaGFuZXMkcmFjZSwgbmhhbmVzJHBhc3Quc21rKQoKCgpgYGAKCkFuIGFzc29jaWF0aW9uIGV4aXN0cyBiZXR3ZWVuIHJhY2UgYW5kIGN1cnJlbnQgc21va2luZy4gQmxhY2sgaW5kaXZpZHVhbHMgdGVuZCB0byBzbW9rZSBtb3JlIHRoYW4gd2hpdGUgb3Igb3RoZXIgaW5kaXZpZHVhbHMuIEFuIGFzc29jaWF0aW9uIGV4aXN0cyBiZXR3ZWVuIHNleCBhbmQgY3VycmVudCBzbW9rZSBzdGF0dXMuIEZlbWFsZSB0ZW5kIHRvIHNtb2tlIGN1cnJlbnRseSBzbGlnaHQgbW9yZSB0aGFuIG1hbGVzIGluIHRoaXMgcG9wdWxhdGlvbi4gCgoKCiMgTUlTU0lORyBWQUxVRVMKCiMjIEltcHV0YXRpb24gZm9yIENhdGVnb3JpY2FsIEZlYXR1cmVzCgpUaGUgZGlzdHJpYnV0aW9uIG9mIG1pc3NpbmcgdmFsdWVzIGZvciBpcyBleGFtaW5lZCB0byBkZXRlcm1pbmUgYW55IHBhdHRlcm5zLiBUaGlzIHN0ZXAgaXMgZG9uZSB0byBlbnN1cmUgdGhhdCB2YWx1ZSBhcmUgbWlzc2luZyBhdCByYW5kb20uIAoKYGBge3J9CiMgU2V0IHVwIGEgMngyIHBsb3R0aW5nIGdyaWQKcGFyKG1mcm93ID0gYygyLCAyKSkKCiNzdW0oaXMubmEobmhhbmVzJHJhY2UpKQoKI21lYW4oaXMubmEobmhhbmVzJHJhY2UpKQoKI3RhYmxlKG5oYW5lcyRyYWNlLCB1c2VOQSA9ICJpZmFueSIpCgoKI2dncGxvdChuaGFuZXMsIGFlcyh4ID0gZmFjdG9yKHJhY2UpKSkgKwogICNnZW9tX2JhcihmaWxsID0gImJsdWUiKSArCiAgI2xhYnModGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIFJhY2UgKEJlZm9yZSBJbXB1dGF0aW9uKSIsIHggPSAiUmFjZSIsIHkgPSAiQ291bnQiKSArCiAgI3RoZW1lX21pbmltYWwoKQoKCmFnZ3IobmhhbmVzLCBjb2wgPSBjKCJuYXZ5Ymx1ZSIsICJyZWQiKSwgbnVtYmVycyA9IFRSVUUsIHNvcnRWYXJzID0gVFJVRSwgCiAgICAgbGFiZWxzID0gbmFtZXMobmhhbmVzKSwgY2V4LmF4aXMgPSAwLjcsIGdhcCA9IDIsIAogICAgIHlsYWIgPSBjKCJNaXNzaW5nIERhdGEgT3ZlcnZpZXciLCAiUGF0dGVybiBvZiBNaXNzaW5nIERhdGEiKSkKCmBgYAoKQSBwYXR0ZXJuIG9mIG1pc3NpbmcgdmFsdWVzIGV4aXN0cyBiZXR3ZWVuIGJvZHkgd2VpZ2h0LCBCTUksIGFuZCBvYmVzZS4gVGhpcyBwYXR0ZXJuIGNhbiBiZSBleHBsYWluZWQgYnkgdGhlIGZhY3QgdGhhdCBib2R5IHdlaWdodCBpcyB1c2VkIHRvIGNhbGN1bGF0ZSBCTUksIHdoaWNoIGlzIHRoZW4gdXNlZCB0byBjbGFzc2lmeSBvYnNlcnZhdGlvbnMgZm9yIG9iZXNlLiBIb3dldmVyLCB0aGUgcGF0dGVybiBvZiBtaXNzaW5nIHZhbHVlIGFwcGVhcnMgdG8gYmUgcmFuZG9tIGZvciB0aGUgb3RoZXIgZmVhdHVyZXMuIAoKTm8gcGF0dGVybiBvZiBtaXNzaW5nIHZhbHVlcyBleGlzdHMgYmV0d2VlbiByYWNlIGFuZCBvdGhlciBmZWF0dXJlcywgSW4gdHVybiwga05OIGltcHV0YXRpb24gaXMgdXNlZCBmb3IgbWlzc2luZyB2YWx1ZXMgb2YgcmFjZS4gIAoKCgpgYGB7cn0KCnN1bShpcy5uYShuaGFuZXMkcmFjZSkpCnRhYmxlKG5oYW5lcyRyYWNlLCB1c2VOQSA9ICJpZmFueSIpICAjIENoZWNrIGRpc3RyaWJ1dGlvbiBpbmNsdWRpbmcgTkFzCgoKIyBQZXJmb3JtIEtOTiBJbXB1dGF0aW9uIChzaW5nbGUgaW1wdXRhdGlvbikKbmhhbmVzX2ltcHV0ZWQgPC0ga05OKG5oYW5lcywgdmFyaWFibGUgPSAicmFjZSIsIGsgPSAzKQoKIyBLZWVwIG9ubHkgdGhlIG9yaWdpbmFsIGNvbHVtbnMgKHdpdGhvdXQgZXh0cmEgY29sdW1ucyBhZGRlZCBieSBrTk4pCm5oYW5lc19pbXB1dGVkIDwtIG5oYW5lc19pbXB1dGVkWywgbmFtZXMobmhhbmVzKV0KCgoKIyBDT01QQVJFIGJlZm9yZSBhbmQgYWZ0ZXIgaW1wdXRhdGlvbiBkaXN0cmlidXRpb24KCnBhcihtZnJvdyA9IGMoMSwyKSkgICMgU3BsaXQgcGxvdHRpbmcgYXJlYSBpbnRvIHR3bwoKIyBDb252ZXJ0IHJhY2UgdG8gYSBmYWN0b3IgZm9yIGJldHRlciB2aXN1YWxpemF0aW9uCm5oYW5lcyRyYWNlIDwtIGFzLmZhY3RvcihuaGFuZXMkcmFjZSkKbmhhbmVzX2ltcHV0ZWQkcmFjZSA8LSBhcy5mYWN0b3IobmhhbmVzX2ltcHV0ZWQkcmFjZSkKCiMgQ3JlYXRlIGEgbmV3IGNvbHVtbiB0byBpbmRpY2F0ZSB3aGV0aGVyIHRoZSBkYXRhIGlzIG9yaWdpbmFsIG9yIGltcHV0ZWQKbmhhbmVzJHNvdXJjZSA8LSAiQmVmb3JlIEltcHV0YXRpb24iCm5oYW5lc19pbXB1dGVkJHNvdXJjZSA8LSAiQWZ0ZXIgSW1wdXRhdGlvbiIKCiMgQ29tYmluZSBib3RoIGRhdGFzZXRzCm5oYW5lc19jb21wYXJlIDwtIGJpbmRfcm93cyhuaGFuZXMsIG5oYW5lc19pbXB1dGVkKQoKIyBQbG90IHRoZSBkaXN0cmlidXRpb24gYmVmb3JlIGFuZCBhZnRlciBpbXB1dGF0aW9uCmdncGxvdChuaGFuZXNfY29tcGFyZSwgYWVzKHggPSByYWNlLCBmaWxsID0gc291cmNlKSkgKwogIGdlb21fYmFyKHBvc2l0aW9uID0gImRvZGdlIikgKwogIGxhYnModGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIFJhY2UgQmVmb3JlIGFuZCBBZnRlciBJbXB1dGF0aW9uIiwKICAgICAgIHggPSAiUmFjZSIsCiAgICAgICB5ID0gIkNvdW50IiwKICAgICAgIGZpbGwgPSAiRGF0YXNldCIpICsKICB0aGVtZV9taW5pbWFsKCkKCmltcHV0ZWRfbmhhbmVzIDwtIG5oYW5lc19pbXB1dGVkCgoKYGBgClRoZSBvdmVyYWxsIGRpc3RyaWJ1dGlvbiBvZiByYWNlIGFmdGVyIGltcHV0YXRpb24gY2hhbmdlZCBzbGlnaHRseSBhZnRlciBpbXB1dGF0aW9uLgoKCiMjIFJlZ3Jlc3Npb24tQmFzZWQgSW1wdXRhdGlvbiBmb3IgTnVtZXJpY2FsIEZlYXR1cmUKClRoZSBwYXR0ZXJuIG9mIG1pc3NpbmcgdmFsdWVzIGZvciBib2R5IHdlaWdodCBhbmQgY2hvbGVzdGVyb2wgaXMgZXhhbWluZWQgZm9yIGFueSBwb3RlbnRpYWwgcGF0dGVybnMuCgpgYGB7cn0KCgojdmlzX21pc3MobmhhbmVzWywgYygiYm9keS53ZWlnaHQiLCAiY2hvbGVzdHJvbCIpXSkKCgojIFNldCBzbWFsbGVyIGZvbnQgc2l6ZSBmb3IgdGhlIHBsb3QKcGFyKGNleCA9IDAuNCkgICMgQWRqdXN0IHRoaXMgdmFsdWUgZm9yIGRlc2lyZWQgZm9udCBzaXplCgojIEdlbmVyYXRlIHRoZSBtaXNzaW5nIGRhdGEgcGF0dGVybiBwbG90CgptZC5wYXR0ZXJuKGltcHV0ZWRfbmhhbmVzKQoKIyBSZXNldCBncmFwaGljcyBzZXR0aW5ncyAob3B0aW9uYWwpCnBhcihjZXggPSAxKQoKCmBgYApBIHBhdHRlcm4gb2YgbWlzc2luZyB2YWx1ZXMgZXhpc3RzIGJldHdlZW4gYm9keSB3ZWlnaHQsIEJNSSwgYW5kIG9iZXNlIGJlY2F1c2UKCgpCb2R5IHdlaWdodCBpcyBjb3JyZWxhdGVkIHdpdGggaGVpZ2h0LCBhdmVyYWdlIGRpYXN0b2xpYyBibG9vZCBwcmVzc3VyZSwgYW5kIHNleC4gSW4gdHVybiwgdGhlIG1pc3NpbmcgYm9keSB3ZWlnaHQgdmFsdWVzIHdpbGwgYmUgaW1wdXRlZCB1c2luZyBhIHJlZ3Jlc3Npb24gbW9kZWwgdXNpbmcgc2FpZCBleHBsYW5hdG9yeSBmZWF0dXJlcy4gCgpgYGB7cn0KCiMgU3Vic2V0IG5oYW5lcyB0byBjb250YWluIG9ubHkgY29tcGxldGUgb2JzZXJ2YXRpb25zIGZvciBzZWxlY3RlZCB2YXJpYWJsZXMKY29tcGxldGVfbmhhbmVzIDwtIGltcHV0ZWRfbmhhbmVzW2NvbXBsZXRlLmNhc2VzKGltcHV0ZWRfbmhhbmVzWywgYygiYm9keS53ZWlnaHQiLCAiaGVpZ2h0IiwgImF2Zy5kYnAiLCAic2V4IildKSwgXQoKIyBGaXQgdGhlIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsCm1vZGVsX2JvZHkud2VpZ2h0IDwtIGxtKGJvZHkud2VpZ2h0IH4gaGVpZ2h0ICsgYXZnLmRicCArIHNleCwgZGF0YSA9IGNvbXBsZXRlX25oYW5lcykKCiMgVmlldyB0aGUgbW9kZWwgc3VtbWFyeQpzdW1tYXJ5KG1vZGVsX2JvZHkud2VpZ2h0KQoKIyBQbG90IHRoZSByZXNpZHVhbHMKcGxvdChtb2RlbF9ib2R5LndlaWdodCRyZXNpZHVhbHMpCgoKYGBgCgoKVGhlIHJlc2lkdWFsIHBsb3Qgc2hvd3Mgbm8gcGF0dGVybnMuIEluIHR1cm4sIHRoZSBtb2RlbCBmaXQgdGhlIGRhdGEgd2VsbCBhbmQgdGhlIGFzc3VtcHRpb24gb2YgY29uc3RhbnQgdmFyaWFuY2Ugb2YgcmVzaWR1YWxzIGlzIHNhdGlzZmllZC4KCmBgYHtyfQoKIyBDcmVhdGUgYSBjb3B5IG9mIHRoZSBkYXRhc2V0IHRvIHdvcmsgd2l0aAojaW1wdXRlZF9uaGFuZXMgPC0gY29tcGxldGVfbmhhbmVzCgpjb2xTdW1zKGlzLm5hKGltcHV0ZWRfbmhhbmVzKSkKIyBJZGVudGlmeSB0aGUgcm93cyB3aXRoIG1pc3NpbmcgdmFsdWVzIGZvciBib2R5LndlaWdodAptaXNzaW5nX2JvZHlfd2VpZ2h0IDwtIGlzLm5hKGltcHV0ZWRfbmhhbmVzJGJvZHkud2VpZ2h0KQoKIyBVc2UgdGhlIG1vZGVsIHRvIHByZWRpY3QgdGhlIG1pc3NpbmcgdmFsdWVzCmltcHV0ZWRfbmhhbmVzJGJvZHkud2VpZ2h0W21pc3NpbmdfYm9keV93ZWlnaHRdIDwtIHByZWRpY3QobW9kZWxfYm9keS53ZWlnaHQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSBpbXB1dGVkX25oYW5lc1ttaXNzaW5nX2JvZHlfd2VpZ2h0LCBjKCJoZWlnaHQiLCAiYXZnLmRicCIsICJzZXgiLCAiYWdlIildKQoKIyBDaGVjayB0aGUgZGF0YXNldAojaGVhZChpbXB1dGVkX25oYW5lcykKCiMgQ3JlYXRlIGEgcGxvdCB0byBvdmVybGF5IHRoZSBkZW5zaXR5IGN1cnZlcwpnZ3Bsb3QoKSArCiAgZ2VvbV9kZW5zaXR5KGRhdGEgPSBjb21wbGV0ZV9uaGFuZXMsIGFlcyh4ID0gYm9keS53ZWlnaHQpLCBmaWxsID0gImJsdWUiLCBhbHBoYSA9IDAuMiwgbmEucm0gPSBUUlVFKSArIAogIGdlb21fZGVuc2l0eShkYXRhID0gaW1wdXRlZF9uaGFuZXMsIGFlcyh4ID0gYm9keS53ZWlnaHQpLCBmaWxsID0gInJlZCIsIGFscGhhID0gMC4yLCBuYS5ybSA9IFRSVUUpICsKICBsYWJzKHRpdGxlID0gIkRlbnNpdHkgUGxvdCBvZiBCb2R5IFdlaWdodDogQmVmb3JlIGFuZCBBZnRlciBJbXB1dGF0aW9uIiwKICAgICAgIHggPSAiQm9keSBXZWlnaHQiLCB5ID0gIkRlbnNpdHkiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBzY2FsZV9maWxsX21hbnVhbChuYW1lID0gIkJvZHkgV2VpZ2h0IiwgdmFsdWVzID0gYygiYmx1ZSIgPSAiYmx1ZSIsICJyZWQiID0gInJlZCIpLCAKICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJCZWZvcmUgSW1wdXRhdGlvbiIsICJBZnRlciBJbXB1dGF0aW9uIikpCgoKYGBgCgoKVGhlIGRpc3RyaWJ1dGlvbiBiZWZvcmUgYW5kIGFmdGVyIGltcHV0YXRpb24gaXMgc2ltaWxhci4gSW4gdHVybiwgdGhlIGltcHV0YXRpb24gZGlkIG5vdCBjaGFuZ2UgdGhlIGRpc3RyaWJ1dGlvbiBvZiBib2R5IHdlaWdodC4gCgoKCgpUaGUgZmVhdHVyZXMgdGhhdCBhcmUgbW9zdCBjb3JyZWxhdGVkIHRvIGNob2xlc3Rlcm9sIGFyZSBhZ2UsIGF2ZXJhZ2Ugc3lzdG9saWMgYmxvb2QgcHJlc3N1cmUsIGFuZCBib2R5IHdlaWdodC4gSW4gdHVybiwgdGhlIG1pc3NpbmcgdmFsdWVzIG9mIGNob2xlc3Rlcm9sIHdpbGwgYmUgaW1wdXRlZCB3aXRoIGEgbW9kZWwgdXNpbmcgdGhlc2UgZmVhdHVyZXMuIAoKYGBge3J9CgojIFN1YnNldCBuaGFuZXMgdG8gaW5jbHVkZSBvbmx5IHJvd3Mgd2l0aCBjb21wbGV0ZSBjYXNlcyBmb3IgY2hvbGVzdHJvbCwgYWdlLCBhdmcuc2JwLCBhbmQgQk1JCmNvbXBsZXRlX25oYW5lcyA8LSBpbXB1dGVkX25oYW5lc1shaXMubmEoaW1wdXRlZF9uaGFuZXMkY2hvbGVzdHJvbCkgJiAhaXMubmEoaW1wdXRlZF9uaGFuZXMkYWdlKSAmIAogICAgICAgICAgICAgICAgICAgICAgICAgICAhaXMubmEoaW1wdXRlZF9uaGFuZXMkYXZnLnNicCkgJiAhaXMubmEoaW1wdXRlZF9uaGFuZXMkYm9keS53ZWlnaHQpLCBdCgpjb21wbGV0ZV9uaGFuZXMgPC0gaW1wdXRlZF9uaGFuZXNbY29tcGxldGUuY2FzZXMoaW1wdXRlZF9uaGFuZXNbLCBjKCJjaG9sZXN0cm9sIiwgImFnZSIsICJhdmcuc2JwIiwgImJvZHkud2VpZ2h0IildKSwgXQoKIyBGaXQgdGhlIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsIHRvIHByZWRpY3QgY2hvbGVzdHJvbAptb2RlbF9jaG9sZXN0cm9sIDwtIGxtKGNob2xlc3Ryb2wgfiBhZ2UgKyBhdmcuc2JwICsgYm9keS53ZWlnaHQsIGRhdGEgPSBjb21wbGV0ZV9uaGFuZXMpCnN1bW1hcnkobW9kZWxfY2hvbGVzdHJvbCkKCgojIFZpZXcgdGhlIG1vZGVsIHN1bW1hcnkKc3VtbWFyeShtb2RlbF9jaG9sZXN0cm9sKQoKIyBDcmVhdGUgYSBjb3B5IG9mIG5oYW5lcyBmb3IgaW1wdXRhdGlvbgojaW1wdXRlZF9uaGFuZXMgPC0gbmhhbmVzCgojIElkZW50aWZ5IHJvd3Mgd2l0aCBtaXNzaW5nIGNob2xlc3Ryb2wgdmFsdWVzCm1pc3NpbmdfY2hvbGVzdHJvbCA8LSBpcy5uYShpbXB1dGVkX25oYW5lcyRjaG9sZXN0cm9sKQoKIyBVc2UgdGhlIG1vZGVsIHRvIHByZWRpY3QgdGhlIG1pc3NpbmcgY2hvbGVzdHJvbCB2YWx1ZXMKaW1wdXRlZF9uaGFuZXMkY2hvbGVzdHJvbFttaXNzaW5nX2Nob2xlc3Ryb2xdIDwtIHByZWRpY3QobW9kZWxfY2hvbGVzdHJvbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXdkYXRhID0gaW1wdXRlZF9uaGFuZXNbbWlzc2luZ19jaG9sZXN0cm9sLCBjKCJhZ2UiLCAiYXZnLnNicCIsICJib2R5LndlaWdodCIpXSkKCgpgYGAKCkFsbCBleHBsYW5hdG9yeSBmZWF0dXJlcyBhcmUgc2lnbmlmaWNhbnQuIAoKYGBge3J9CiMgR2V0IHJlc2lkdWFscyBmcm9tIHRoZSBtb2RlbCBmb3IgY29tcGxldGVfbmhhbmVzCnJlc2lkdWFsc19jaG9sZXN0cm9sIDwtIHJlc2lkdWFscyhtb2RlbF9jaG9sZXN0cm9sKQoKIyBQcmVkaWN0ZWQgdmFsdWVzIGZvciBjb21wbGV0ZV9uaGFuZXMKcHJlZGljdGVkX2Nob2xlc3Ryb2wgPC0gcHJlZGljdChtb2RlbF9jaG9sZXN0cm9sLCBuZXdkYXRhID0gY29tcGxldGVfbmhhbmVzKQoKIyBDcmVhdGUgYSBkYXRhIGZyYW1lIGZvciByZXNpZHVhbHMgYW5kIHByZWRpY3RlZCB2YWx1ZXMKcmVzaWR1YWxzX2RhdGEgPC0gZGF0YS5mcmFtZSgKICBwcmVkaWN0ZWRfY2hvbGVzdHJvbCA9IHByZWRpY3RlZF9jaG9sZXN0cm9sLAogIHJlc2lkdWFsc19jaG9sZXN0cm9sID0gcmVzaWR1YWxzX2Nob2xlc3Ryb2wKKQoKIyBDcmVhdGUgdGhlIHJlc2lkdWFsIHBsb3QKbGlicmFyeShnZ3Bsb3QyKQpnZ3Bsb3QocmVzaWR1YWxzX2RhdGEsIGFlcyh4ID0gcHJlZGljdGVkX2Nob2xlc3Ryb2wsIHkgPSByZXNpZHVhbHNfY2hvbGVzdHJvbCkpICsKICBnZW9tX3BvaW50KGNvbG9yID0gImJsdWUiKSArICAjIFBsb3QgdGhlIHJlc2lkdWFscwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gInJlZCIpICsgICMgQWRkIGEgaG9yaXpvbnRhbCBsaW5lIGF0IDAKICBsYWJzKHRpdGxlID0gIlJlc2lkdWFsIFBsb3QgZm9yIENob2xlc3Ryb2wgUHJlZGljdGlvbiIsCiAgICAgICB4ID0gIlByZWRpY3RlZCBDaG9sZXN0cm9sIiwKICAgICAgIHkgPSAiUmVzaWR1YWxzIikgKwogIHRoZW1lX21pbmltYWwoKQoKIyBDcmVhdGUgdGhlIG92ZXJsYXkgZGVuc2l0eSBwbG90CmdncGxvdCgpICsKICBnZW9tX2RlbnNpdHkoZGF0YSA9IG5oYW5lcywgYWVzKHggPSBjaG9sZXN0cm9sKSwgZmlsbCA9ICJibHVlIiwgYWxwaGEgPSAwLjIsIG5hLnJtID0gVFJVRSkgKyAgIyBCZWZvcmUgaW1wdXRhdGlvbgogIGdlb21fZGVuc2l0eShkYXRhID0gaW1wdXRlZF9uaGFuZXMsIGFlcyh4ID0gY2hvbGVzdHJvbCksIGZpbGwgPSAicmVkIiwgYWxwaGEgPSAwLjIsIG5hLnJtID0gVFJVRSkgKyAgIyBBZnRlciBpbXB1dGF0aW9uCiAgbGFicyh0aXRsZSA9ICJEZW5zaXR5IFBsb3Qgb2YgQ2hvbGVzdHJvbDogQmVmb3JlIGFuZCBBZnRlciBJbXB1dGF0aW9uIiwKICAgICAgIHggPSAiQ2hvbGVzdHJvbCIsIHkgPSAiRGVuc2l0eSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWUgPSAiQ2hvbGVzdHJvbCIsIHZhbHVlcyA9IGMoImJsdWUiID0gImJsdWUiLCAicmVkIiA9ICJyZWQiKSwgCiAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiQmVmb3JlIEltcHV0YXRpb24iLCAiQWZ0ZXIgSW1wdXRhdGlvbiIpKQoKCmBgYAoKVGhlIGRpc3RyaWJ1dGlvbiBvZiBjaG9sZXN0ZXJvbCBkaWQgbm90IGNoYW5nZSBzaWduaWZpY2FudGx5IGFmdGVyIGltcHV0YXRpb24uIEFzIHdlbGwsIHRoZSByZXNpZHVhbCBwbG90IGRvZXMgbm90IGRpc3BsYXkgYW55IHBhdHRlcm5zLiBJbiB0dXJuLCB0aGUgbW9kZWwgZml0IHRoZSBkYXRhIHdlbGwgYW5kIHRoZSBhc3N1bXB0aW9uIG9mIGNvbnN0YW50IHZhcmlhbmNlIG9mIHJlc2lkdWFscyBpcyBzYXRpc2ZpZWQuIAoKIyMgRmVhdHVyZSBFbmdpbmVlcgoKSW4gdHVybiBhIGZlYXR1cmUgd2hpY2ggY2FsY3VsYXRlcyBCTUkgaXMgY3JlYXRlZCB0byBkZXRlcm1pbmUgb2JzZXJ2YXRpb25zIGFyZSBjbGFzc2lmaWVkIGFzIG9iZXNlLiBBY2NvcmRpbmcgdG8gdGhlIENEQyAoaHR0cHM6Ly93d3cuY2RjLmdvdi9uY2NkcGhwL2RucGFvL2RhdGEtdHJlbmRzLW1hcHMvaGVscC9ucGFvX2R0bS9kZWZpbml0aW9ucy5odG1sKSwgQWR1bHQgb2Jlc2l0eSBpcyBkZWZpbmVkIGFzIGJvZHkgbWFzcyBpbmRleCAoQk1JKSDiiaUgMzAuMC4gQW5vdGhlciBmZWF0dXJlIG5hbWVkIG9iZXNlLCBiYXNlZCBvbiBCTUksIGlzIGNyZWF0ZWQsIHdoZXJlIDAgPSBubyBhbmQgMSA9IHllcy4gCgpgYGB7cn0KCiMgQ3JlYXRlIEJNSSBmZWF0dXJlCmltcHV0ZWRfbmhhbmVzJEJNSSA8LSAoaW1wdXRlZF9uaGFuZXMkYm9keS53ZWlnaHQgKiA3MDMpIC8gKGltcHV0ZWRfbmhhbmVzJGhlaWdodCAqIGltcHV0ZWRfbmhhbmVzJGhlaWdodCkKIyBSb3VuZCB0aGUgQk1JIHRvIHRoZSBuZWFyZXN0IG9uZXMgcGxhY2UKaW1wdXRlZF9uaGFuZXMkQk1JIDwtIHJvdW5kKGltcHV0ZWRfbmhhbmVzJEJNSSwgMCkKCiMgQ3JlYXRlIHRoZSBvYmVzZSBmZWF0dXJlIGJhc2VkIG9uIEJNSQppbXB1dGVkX25oYW5lcyRvYmVzZSA8LSBpZmVsc2UoaW1wdXRlZF9uaGFuZXMkQk1JID49IDMwLCAxLCAwKQoKYGBgCgpgYGB7cn0KCnBhcihtZnJvdyA9IGMoMSwgMikpCgojIEhpc3RvZ3JhbSBmb3IgQk1JCgpoaXN0KGltcHV0ZWRfbmhhbmVzJEJNSSwgCiAgICAgbWFpbiA9ICJIaXN0b2dyYW0gb2YgQk1JIiwgCiAgICAgeGxhYiA9ICJCTUkiLCAKICAgICBjb2wgPSAic3RlZWxibHVlIiwgCiAgICAgYm9yZGVyID0gImJsYWNrIiwgCiAgICAgYnJlYWtzID0gMjApCgojIGJhciBjaGFydCBmb3Igb2Jlc2UKbmhhbmVzJG9iZXNlIDwtIGZhY3RvcihpbXB1dGVkX25oYW5lcyRvYmVzZSwgbGV2ZWxzID0gYygwLCAxKSwgbGFiZWxzID0gYygiTm8iLCAiWWVzIikpCgpvYmVzZV9jb3VudCA8LSB0YWJsZShpbXB1dGVkX25oYW5lcyRvYmVzZSkKCmJhcnBsb3QoaGVpZ2h0ID0gb2Jlc2VfY291bnQsIGNvbCA9ICJzdGVlbGJsdWUiLCBtYWluID0gIk9iZXNpdHkiLCB4bGFiID0gIk9iZXNpdHkiLCB5bGFiID0gIkNvdW50IikKCgpgYGAKCgpgYGB7cn0KIyBTZXQgdXAgYSAyeDIgcGxvdHRpbmcgZ3JpZApwYXIobWZyb3cgPSBjKDIsIDIpKQoKCiMgQ3JlYXRlIGEgY29udGluZ2VuY3kgdGFibGUKb2Jlc2VfaGJwX3RhYmxlIDwtIHRhYmxlKGltcHV0ZWRfbmhhbmVzJG9iZXNlLCBpbXB1dGVkX25oYW5lcyRoYnApCgojIEdlbmVyYXRlIG1vc2FpYyBwbG90Cm1vc2FpY3Bsb3Qob2Jlc2VfaGJwX3RhYmxlLCAKICAgICAgICAgICBjb2wgPSBjKCJnb2xkIiwgInJveWFsYmx1ZSIpLCAKICAgICAgICAgICBtYWluID0gIk9iZXNpdHkgYW5kIEhpZ2ggQmxvb2QgUHJlc3N1cmUiLAogICAgICAgICAgIHhsYWIgPSAiT2Jlc2l0eSBTdGF0dXMiLCAKICAgICAgICAgICB5bGFiID0gIkhCUCBTdGF0dXMiLAogICAgICAgICAgIGJvcmRlciA9ICJibGFjayIpCgojIENyZWF0ZSBhIGNvbnRpbmdlbmN5IHRhYmxlCm9iZXNlX3NleF90YWJsZSA8LSB0YWJsZShpbXB1dGVkX25oYW5lcyRzZXgsIGltcHV0ZWRfbmhhbmVzJG9iZXNlKQoKIyBHZW5lcmF0ZSBtb3NhaWMgcGxvdAptb3NhaWNwbG90KG9iZXNlX3NleF90YWJsZSwgCiAgICAgICAgICAgY29sID0gYygiZ29sZCIsICJyb3lhbGJsdWUiKSwgCiAgICAgICAgICAgbWFpbiA9ICJTZXggYW5kIE9iZXNpdHkiLAogICAgICAgICAgIHhsYWIgPSAiT2Jlc2l0eSBTdGF0dXMiLCAKICAgICAgICAgICB5bGFiID0gIlNleCIsCiAgICAgICAgICAgYm9yZGVyID0gImJsYWNrIikKCgojIENyZWF0ZSBhIGNvbnRpbmdlbmN5IHRhYmxlCm9iZXNlX3JhY2VfdGFibGUgPC0gdGFibGUoaW1wdXRlZF9uaGFuZXMkcmFjZSwgaW1wdXRlZF9uaGFuZXMkb2Jlc2UpCgojIEdlbmVyYXRlIG1vc2FpYyBwbG90Cm1vc2FpY3Bsb3Qob2Jlc2VfcmFjZV90YWJsZSwgCiAgICAgICAgICAgY29sID0gYygiZ29sZCIsICJyb3lhbGJsdWUiKSwgCiAgICAgICAgICAgbWFpbiA9ICJSYWNlIGFuZCBPYmVzaXR5IiwKICAgICAgICAgICB4bGFiID0gIk9iZXNpdHkgU3RhdHVzIiwgCiAgICAgICAgICAgeWxhYiA9ICJSYWNlIiwKICAgICAgICAgICBib3JkZXIgPSAiYmxhY2siKQoKCiMgQ3JlYXRlIGEgY29udGluZ2VuY3kgdGFibGUKb2Jlc2Vfc21va2VfdGFibGUgPC0gdGFibGUoaW1wdXRlZF9uaGFuZXMkY3VycmVudC5zbWssIGltcHV0ZWRfbmhhbmVzJG9iZXNlKQoKIyBHZW5lcmF0ZSBtb3NhaWMgcGxvdAptb3NhaWNwbG90KG9iZXNlX3Ntb2tlX3RhYmxlLCAKICAgICAgICAgICBjb2wgPSBjKCJnb2xkIiwgInJveWFsYmx1ZSIpLCAKICAgICAgICAgICBtYWluID0gIkN1cnJlbnQgU21va2luZyBTdGF0dXMgYW5kIE9iZXNpdHkiLAogICAgICAgICAgIHhsYWIgPSAiT2Jlc2l0eSBTdGF0dXMiLCAKICAgICAgICAgICB5bGFiID0gIkN1cnJlbnQgU21va2luZyBTdGF0dXMiLAogICAgICAgICAgIGJvcmRlciA9ICJibGFjayIpCgoKYGBgCgoKCgoKIyMgTXVsdGlwbGUgSW1wdXRhdGlvbgoKTXVsdGlwbGUgSW1wdXRhdGlvbiBieSBDaGFpbmVkIEVxdWF0aW9ucyAoTUlDRSkgaXMgYSBwb3dlcmZ1bCB0ZWNobmlxdWUgdXNlZCB0byBoYW5kbGUgbWlzc2luZyBkYXRhIGJ5IGNyZWF0aW5nIG11bHRpcGxlIHBsYXVzaWJsZSBpbXB1dGF0aW9ucyBmb3IgZWFjaCBtaXNzaW5nIHZhbHVlIGJhc2VkIG9uIHJlbGF0aW9uc2hpcHMgaW4gdGhlIG9ic2VydmVkIGRhdGEuIEZvciBib2R5IHdlaWdodCwgY2hvbGVzdGVyb2wsIGFuZCByYWNlLCBNSUNFIGNhbiBiZSBhcHBsaWVkIHRvIGdlbmVyYXRlIGFjY3VyYXRlIGltcHV0YXRpb25zLCBhY2NvdW50aW5nIGZvciBjb3JyZWxhdGlvbnMgYmV0d2VlbiB0aGVzZSB2YXJpYWJsZXMgYW5kIG90aGVyIGZlYXR1cmVzIGluIHRoZSBkYXRhc2V0LiBUaGlzIG1ldGhvZCBhbGxvd3MgZm9yIG1vcmUgcmVsaWFibGUgc3RhdGlzdGljYWwgYW5hbHlzZXMgYnkgcmVkdWNpbmcgYmlhcyBhbmQgcHJlc2VydmluZyB2YXJpYWJpbGl0eSBpbiB0aGUgaW1wdXRlZCB2YWx1ZXMsIG1ha2luZyBpdCBlc3BlY2lhbGx5IHVzZWZ1bCBmb3IgaGFuZGxpbmcgbWlzc2luZyBkYXRhIGluIGluY29taW5nIG5ldyBkYXRhIHNldHMuCgpgYGB7cn0KCm5oYW5lczEkcmFjZSA8LSBhcy5mYWN0b3IobmhhbmVzMSRyYWNlKSAgCm5oYW5lczEkY2hvbGVzdHJvbCA8LSBhcy5udW1lcmljKG5oYW5lczEkY2hvbGVzdHJvbCkKbmhhbmVzMSRib2R5LndlaWdodCA8LSBhcy5udW1lcmljKG5oYW5lczEkYm9keS53ZWlnaHQpCgpuaGFuZXMyIDwtIG5oYW5lczEKCgojIDEgaW5pdGlhbGl6YXRpb24KCmluaXQgPC0gbWljZShuaGFuZXMyLCBtYXhpdD0wKQpwcmludChpbml0JG1ldGhvZCkKCgojIDIgaW1wdXRhdGlvbiBtb2RlbHMKCmltcCA8LSBtaWNlKG5oYW5lczIsIG1ldGhvZCA9IGMoIiIsICIiLCAiIiwgIiIsICIiLCAiIiwgIiIsICJwb2x5cmVnIiwgInBtbSIsICIiLCAiIiwgIiIsICIiLCAiIiwgInBtbSIsICIiKSwgCiAgICAgICAgICAgIG1heGl0PTEwLAogICAgICAgICAgICBtPTEsCiAgICAgICAgICAgIHNlZWQgPSAxMjMsCiAgICAgICAgICAgIHByaW50PUYpCgpjb21wbGV0ZShpbXAsIGFjdGlvbiA9IDEpWzE6MTAsXQoKCiMgMyBtdWx0aXBsZSAoaXRlcmF0aXZlKSBpbXB1dGF0aW9ucwoKaW1wNSA8LSBtaWNlKG5oYW5lczIsIG1ldGhvZCA9ICJwbW0iLCBtID0gNSwgbWF4aXQgPSAxMCwgc2VlZCA9IDEyMywgcHJpbnQ9RikKcGxvdChpbXA1KQoKCgpgYGAKCgpNdWx0aXBsZSBJbXB1dGF0aW9uIGJ5IENoYWluZWQgRXF1YXRpb25zIChNSUNFKSB3aWxsIGJlIGFwcGxpZWQgdG8gaGFuZGxlIG1pc3NpbmcgdmFsdWVzIGluIHRoZSBib2R5IHdlaWdodCB2YXJpYWJsZS4gVG8gYXNzZXNzIHRoZSBxdWFsaXR5IG9mIHRoZSBpbXB1dGF0aW9ucywgdGhlIE1lYW4gU3F1YXJlZCBFcnJvciAoTVNFKSB3aWxsIGJlIGNhbGN1bGF0ZWQgYW5kIGNvbXBhcmVkIHRoZSBNU0Ugb2YgdGhlIHNpbmdsZSBpbXB1dGF0aW9uIGNvbmR1Y3RlZCBmb3IgYm9keSB3ZWlnaHQgZWFybGllciBpbiB0aGlzIGFuYWx5c2lzLCBwcm92aWRpbmcgYSBtZWFzdXJlIG9mIHRoZSBpbXB1dGF0aW9uIGFjY3VyYWN5LgoKCmBgYHtyfQptb2RlbDVfYm9keXdlaWdodCA8LSB3aXRoKGltcDUsIGxtKGJvZHkud2VpZ2h0IH4gaGVpZ2h0ICsgYXZnLmRicCArIHNleCkpCnN1bW1hcnkuc3RhdHMgPSBzdW1tYXJ5KG1vZGVsNV9ib2R5d2VpZ2h0KQoKc3VtbWFyeShwb29sKG1vZGVsNV9ib2R5d2VpZ2h0KSkKCmJldGEgPSBzdW1tYXJ5LnN0YXRzJGVzdGltYXRlW3NlcSgxLDE1LGJ5PTMpXSAgIyBleHBsaWNpdCB2ZWN0b3I6IGMoMSw0LDcsMTAsMTMpCmJldGEudmFyID0gKHN1bW1hcnkuc3RhdHMkc3RkLmVycm9yW3NlcSgxLDE1LGJ5PTMpXSleMiAKUSA9IG1lYW4oYmV0YSkKVSA9IG1lYW4oYmV0YS52YXIpCkIgPSB2YXIoYmV0YSkKVCA9IFUgKyAoNi81KSpCCnBvb2wuc2UgPSBzcXJ0KFQpCmNiaW5kKHBvb2wuc2UuaW50ZXJjZXB0ID0gcG9vbC5zZSkKCgpgYGAKVGhlIG1vZGVsIGNhbiBiZSB1c2VkIHRvIHByZWRpY3QgYm9keSB3ZWlnaHQgZm9yIGluY29taW5nIG5ldyBkYXRhLiAKClRoZSBNU0UgZm9yIHNpbmdsZSBib2R5IHdlaWdodCBpbXB1dGF0aW9uIHVzZWQgZWFybGllciBpbiB0aGlzIGFuYWx5c2lzIGlzIE1TRSA9IChSU0UpXjIgPSAoMzMuNTIpXjIgPSAxMTIzLjYgd2hpY2ggaXMgc3Vic3RhbnRpYWxseSBoaWdoZXIgdGhhbiBNU0Ugd2hlbiB1c2luZyBNSUNFLiBJbiB0dXJuLCBNSUNFIGlzIHJlY29tbWVuZGVkIGluIHRoaXMgYW5hbHlzaXMuIAoKCgpNdWx0aXBsZSBJbXB1dGF0aW9uIGJ5IENoYWluZWQgRXF1YXRpb25zIChNSUNFKSB3aWxsIGJlIGFwcGxpZWQgdG8gaGFuZGxlIG1pc3NpbmcgdmFsdWVzIGluIHRoZSBjaG9sZXN0ZXJvbCB2YXJpYWJsZS4gVG8gYXNzZXNzIHRoZSBxdWFsaXR5IG9mIHRoZSBpbXB1dGF0aW9ucywgdGhlIE1lYW4gU3F1YXJlZCBFcnJvciAoTVNFKSB3aWxsIGJlIGNhbGN1bGF0ZWQgYW5kIGNvbXBhcmVkIHRoZSBNU0Ugb2YgdGhlIHNpbmdsZSBpbXB1dGF0aW9uIGNvbmR1Y3RlZCBmb3IgY2hvbGVzdGVyb2wgZWFybGllciBpbiB0aGlzIGFuYWx5c2lzLCBwcm92aWRpbmcgYSBtZWFzdXJlIG9mIHRoZSBpbXB1dGF0aW9uIGFjY3VyYWN5LgoKYGBge3J9Cm1vZGVsNV9jaG9sIDwtIHdpdGgoaW1wNSwgbG0oY2hvbGVzdHJvbCB+IGFnZSArIGF2Zy5zYnApKQpzdW1tYXJ5LnN0YXRzID0gc3VtbWFyeShtb2RlbDVfY2hvbCkKCgpzdW1tYXJ5KHBvb2wobW9kZWw1X2Nob2wpKQoKYmV0YSA9IHN1bW1hcnkuc3RhdHMkZXN0aW1hdGVbc2VxKDEsMTUsYnk9MyldICAjIGV4cGxpY2l0IHZlY3RvcjogYygxLDQsNywxMCwxMykKYmV0YS52YXIgPSAoc3VtbWFyeS5zdGF0cyRzdGQuZXJyb3Jbc2VxKDEsMTUsYnk9MyldKV4yIApRID0gbWVhbihiZXRhKQpVID0gbWVhbihiZXRhLnZhcikKQiA9IHZhcihiZXRhKQpUID0gVSArICg2LzUpKkIKcG9vbC5zZSA9IHNxcnQoVCkKY2JpbmQocG9vbC5zZS5pbnRlcmNlcHQgPSBwb29sLnNlKQoKCmBgYApUaGUgbW9kZWwgY2FuIGJlIHVzZWQgdG8gcHJlZGljdCBjaG9sZXN0ZXJvbCBmb3IgaW5jb21pbmcgbmV3IGRhdGEuIAoKVGhlIE1lYW4gU3F1YXJlZCBFcnJvciAoTVNFKSBmcm9tIHRoZSBSZXNpZHVhbCBTdGFuZGFyZCBFcnJvciAoUlNFKSBnaXZlbiBpbiB0aGUgbW9kZWwgb3V0cHV0IGZyb20gdGhlIGNob2xlc3Rlcm9sIHNpbmdsZSBpbXB1dGF0aW9uIG1ldGhvZCB1c2VkIGVhcmx5IGluIHRoaXMgYW5hbHlzaXMgaXMgTVNFID0gKDQyLjU5KV4yID0gMTgxMy45LiBUaHVzLCB0aGUgTWVhbiBTcXVhcmVkIEVycm9yIChNU0UpID0gMTgxMy45LgoKVGhlIE1TRSB1c2luZyBNSUNFIGlzIDMuNjYgd2hpY2ggaXMgc3Vic3RhbnRpYWxseSBsZXNzLiBUaGVyZWZvcmUsIE1JQ0UgaXMgcmVjb21tZW5kZWQgaW4gdGhlIGFuYWx5c2lzIG9mIHRoaXMgZGF0YSBzZXQuIAoKCgpGb3IgdGhlIG1pc3NpbmcgdmFsdWVzIGluIHRoZSByYWNlIHZhcmlhYmxlLCBNdWx0aXBsZSBJbXB1dGF0aW9uIGJ5IENoYWluZWQgRXF1YXRpb25zIChNSUNFKSB3aWxsIGJlIGFwcGxpZWQgdXNpbmcgbXVsdGlub21pYWwgbG9naXN0aWMgcmVncmVzc2lvbi4gVGhpcyBtZXRob2Qgd2lsbCBhY2NvdW50IGZvciB0aGUgY2F0ZWdvcmljYWwgbmF0dXJlIG9mIHRoZSByYWNlIHZhcmlhYmxlLCBhbGxvd2luZyBmb3IgYXBwcm9wcmlhdGUgaW1wdXRhdGlvbiBiYXNlZCBvbiB0aGUgcmVsYXRpb25zaGlwcyB3aXRoIG90aGVyIGZlYXR1cmVzIGluIHRoZSBkYXRhc2V0LgoKYGBge3J9Cgptb2RlbF9yYWNlIDwtIHdpdGgoaW1wNSwgbXVsdGlub20ocmFjZSB+IGF2Zy5kYnAgKyBhdmcuc2JwICsgY2hvbGVzdHJvbCArIGhicCkpCgojIFBvb2wgdGhlIHJlc3VsdHMgZnJvbSB0aGUgaW1wdXRlZCBkYXRhc2V0cwpwb29sZWRfcmFjZSA8LSBwb29sKG1vZGVsX3JhY2UpCgojIEdldCBhIHN1bW1hcnkgb2YgdGhlIHBvb2xlZCByZXN1bHRzCnN1bW1hcnkocG9vbGVkX3JhY2UpCgpgYGAKClRoZSBtb2RlbCBjYW4gYmUgdXNlZCB0byBwcmVkaWN0IHJhY2UgZm9yIGluY29taW5nIG5ldyBkYXRhLiAKCgojIEZFQVRVUkUgVFJBTlNGT1JNSU5HCgpCYXNlZCBvbiB0aGUgZGlzdHJpYnV0aW9uIHBhdHRlcm5zIG9ic2VydmVkIGluIHRoZSBOSEFORVMgZGF0YSBzZXQsIHNldmVyYWwgZmVhdHVyZSBlbmdpbmVlcmluZyB0YXNrcyBjYW4gYmUgcGVyZm9ybWVkIHRvIGVuaGFuY2UgdGhlIGRhdGHigJlzIHVzYWJpbGl0eSBmb3IgbW9kZWxpbmcuIEZpcnN0LCBmb3IgYWdlLCB3aGljaCBpcyByb3VnaGx5IHVuaWZvcm0sIG5vIG1ham9yIHRyYW5zZm9ybWF0aW9uIGlzIG5lZWRlZCwgdGhvdWdoIHdlIG1heSBjb25zaWRlciBiaW5uaW5nIGl0IGludG8gYWdlIGdyb3VwcyBpZiBpdCBoZWxwcyB3aXRoIGludGVycHJldGFiaWxpdHkuIEZvciB3ZWlnaHQgYW5kIHN5c3RvbGljIGJsb29kIHByZXNzdXJlIChCUCksIHdoaWNoIGFyZSBib3RoIHNrZXdlZCByaWdodCwgYSBsb2cgdHJhbnNmb3JtYXRpb24gY291bGQgYmUgYXBwbGllZCB0byByZWR1Y2Ugc2tld25lc3MgYW5kIG1ha2UgdGhlc2UgdmFyaWFibGVzIG1vcmUgbm9ybWFsbHkgZGlzdHJpYnV0ZWQsIGltcHJvdmluZyBtb2RlbCBwZXJmb3JtYW5jZS4gU2ltaWxhcmx5LCBmb3IgY2hvbGVzdGVyb2wsIHdoaWNoIGlzIHNsaWdodGx5IHNrZXdlZCByaWdodCwgYSBsb2cgdHJhbnNmb3JtYXRpb24gbWF5IGFsc28gYmUgdXNlZnVsLiBGb3IgZGlhc3RvbGljIEJQLCB3aGljaCBpcyByb3VnaGx5IHN5bW1ldHJpYywgbm8gdHJhbnNmb3JtYXRpb24gaXMgbmVjZXNzYXJ5LCBidXQgY2hlY2tpbmcgZm9yIG91dGxpZXJzIGNvdWxkIGJlIGhlbHBmdWwuIFRoZXNlIHRyYW5zZm9ybWF0aW9ucyBhaW0gdG8gc3RhYmlsaXplIHZhcmlhbmNlLCByZWR1Y2UgdGhlIGltcGFjdCBvZiBleHRyZW1lIHZhbHVlcywgYW5kIGNyZWF0ZSBmZWF0dXJlcyB0aGF0IGFyZSBtb3JlIHN1aXRhYmxlIGZvciBtb2RlbGluZyB3aXRoIHRlY2huaXF1ZXMgbGlrZSBsaW5lYXIgcmVncmVzc2lvbiBvciBvdGhlciBzdGF0aXN0aWNhbCBtZXRob2RzLgoKCmBgYHtyfQojTG9nIHRyYW5zZm9ybWF0aW9uIHRvIHJlZHVjZSBza2V3CgppbXB1dGVkX25oYW5lcyRsb2dfYm9keS53ZWlnaHQgPC0gbG9nKGltcHV0ZWRfbmhhbmVzJGJvZHkud2VpZ2h0KQppbXB1dGVkX25oYW5lcyRsb2dfYXZnLnNicCA8LSBsb2coaW1wdXRlZF9uaGFuZXMkYXZnLnNicCkKaW1wdXRlZF9uaGFuZXMkbG9nX2Nob2xlc3Ryb2wgPC0gbG9nKGltcHV0ZWRfbmhhbmVzJGNob2xlc3Ryb2wpCmltcHV0ZWRfbmhhbmVzJGxvZ19CTUkgPC0gbG9nKGltcHV0ZWRfbmhhbmVzJEJNSSkKCgoKCiMgU2V0IHVwIHRoZSBwbG90dGluZyBhcmVhIHRvIHNob3cgMngyIGdyaWQgb2YgaGlzdG9ncmFtcwpwYXIobWZyb3cgPSBjKDIsIDIpKSAgIyBUaGlzIHdpbGwgY3JlYXRlIGEgMngyIGdyaWQgb2YgcGxvdHMKCiMgSGlzdG9ncmFtIGZvciBMb2ctQ2hvbGVzdGVyb2wKaGlzdChpbXB1dGVkX25oYW5lcyRsb2dfY2hvbGVzdHJvbCwgCiAgICAgbWFpbiA9ICJIaXN0b2dyYW0gb2YgTG9nKENob2xlc3Rlcm9sKSIsIAogICAgIHhsYWIgPSAiTG9nKENob2xlc3Rlcm9sKSIsIAogICAgIGNvbCA9ICJzdGVlbGJsdWUiLCAKICAgICBib3JkZXIgPSAiYmxhY2siLCAKICAgICBicmVha3MgPSAyMCkgIAogICAgCiMgSGlzdG9ncmFtIGZvciBMb2ctQm9keSBXZWlnaHQKaGlzdChpbXB1dGVkX25oYW5lcyRsb2dfYm9keS53ZWlnaHQsIAogICAgIG1haW4gPSAiSGlzdG9ncmFtIG9mIExvZyhCb2R5IFdlaWdodCkiLCAKICAgICB4bGFiID0gIkxvZyhCb2R5IFdlaWdodCkiLCAKICAgICBjb2wgPSAic3RlZWxibHVlIiwgCiAgICAgYm9yZGVyID0gImJsYWNrIiwgCiAgICAgYnJlYWtzID0gMjApIAoKCiMgSGlzdG9ncmFtIGZvciBMb2ctU3lzdG9saWMgQlAKaGlzdChpbXB1dGVkX25oYW5lcyRsb2dfYXZnLnNicCwgCiAgICAgbWFpbiA9ICJIaXN0b2dyYW0gb2YgTG9nKFN5c3RvbGljIEJQKSIsIAogICAgIHhsYWIgPSAiTG9nKFN5c3RvbGljIEJQKSIsIAogICAgIGNvbCA9ICJzdGVlbGJsdWUiLCAKICAgICBib3JkZXIgPSAiYmxhY2siLCAKICAgICBicmVha3MgPSAyMCkKICAgCgojIEhpc3RvZ3JhbSBmb3IgTG9nLUJNSQpoaXN0KGltcHV0ZWRfbmhhbmVzJGxvZ19CTUksIAogICAgIG1haW4gPSAiSGlzdG9ncmFtIG9mIExvZyhCTUkpIiwgCiAgICAgeGxhYiA9ICJMb2coQk1JKSIsIAogICAgIGNvbCA9ICJzdGVlbGJsdWUiLCAKICAgICBib3JkZXIgPSAiYmxhY2siLCAKICAgICBicmVha3MgPSAyMCkKCgpgYGAKClRoZSBkaXN0cmlidXRpb25zIG9mIHRoZXNlIHByZXZpb3VzbHkgc2tld2VkIGZlYXR1cmVzIGFyZSBtb3JlIHN5bW1ldHJpYyBhZnRlciBsb2cgdHJhbnNmb3JtYXRpb25zLiAKCgojIFNUQU5EQVJESVpJTkcKClN0YW5kYXJkaXppbmcgZmVhdHVyZXMgZW5zdXJlcyB0aGF0IHZhcmlhYmxlcyB3aXRoIGRpZmZlcmVudCBzY2FsZXMsIHN1Y2ggYXMgYWdlLCBCTUksIGhlaWdodCwgYW5kIGNob2xlc3Rlcm9sLCBjb250cmlidXRlIGVxdWFsbHkgdG8gdGhlIGFuYWx5c2lzLiBXaXRob3V0IHN0YW5kYXJkaXphdGlvbiwgdmFyaWFibGVzIHdpdGggbGFyZ2VyIHJhbmdlcyBjb3VsZCBkb21pbmF0ZSBtb2RlbCBwZXJmb3JtYW5jZSwgbGVhZGluZyB0byBiaWFzZWQgcmVzdWx0cy4gQnkgc3RhbmRhcmRpemluZyB0aGVzZSBmZWF0dXJlcywgd2UgaW1wcm92ZSBtb2RlbCBhY2N1cmFjeSwgZW5hYmxlIGJldHRlciBjb21wYXJpc29uIGJldHdlZW4gdmFyaWFibGVzLCBhbmQgZW5oYW5jZSB0aGUgZWZmaWNpZW5jeSBvZiBtYWNoaW5lIGxlYXJuaW5nIGFsZ29yaXRobXMsIHBhcnRpY3VsYXJseSBpbiBtb2RlbHMgdGhhdCByZWx5IG9uIGRpc3RhbmNlLWJhc2VkIG9yIGdyYWRpZW50LWJhc2VkIG1ldGhvZHMuCgoKYGBge3J9CgojIFNwZWNpZnkgdGhlIGNvbHVtbnMgdG8gYmUgc3RhbmRhcmRpemVkCmNvbHVtbnNfdG9fc3RhbmRhcmRpemUgPC0gYygiYWdlIiwgIkJNSSIsICJoZWlnaHQiLCAiYm9keS53ZWlnaHQiLCAiY2hvbGVzdHJvbCIsICJhdmcuZGJwIiwgImF2Zy5zYnAiKQoKIyBTdGFuZGFyZGl6ZSB0aGUgc2VsZWN0ZWQgY29sdW1ucwppbXB1dGVkX25oYW5lc1tjb2x1bW5zX3RvX3N0YW5kYXJkaXplXSA8LSBzY2FsZShpbXB1dGVkX25oYW5lc1tjb2x1bW5zX3RvX3N0YW5kYXJkaXplXSkKCiAgCmBgYAoKCgoKCiMgRkVBVFVSRSBTRUxFQ1RJT04KCkZlYXR1cmUgc2VsZWN0aW9uIGlzIGEgY3JpdGljYWwgc3RlcCBpbiBtb2RlbCBidWlsZGluZywgYXMgaXQgaGVscHMgaW1wcm92ZSBtb2RlbCBwZXJmb3JtYW5jZSBieSBpZGVudGlmeWluZyB0aGUgbW9zdCByZWxldmFudCBwcmVkaWN0b3JzIGFuZCByZWR1Y2luZyBvdmVyZml0dGluZy4gSW4gdGhpcyBhbmFseXNpcywgYm90aCBtb2RlbC1iYXNlZCBzZWxlY3Rpb24gYW5kIHJlZ3VsYXJpemF0aW9uLWJhc2VkIHNlbGVjdGlvbiB0ZWNobmlxdWVzIHdpbGwgYmUgdXNlZCB0byBhc3Nlc3MgYW5kIHJldGFpbiB0aGUgbW9zdCBpbmZsdWVudGlhbCBmZWF0dXJlcyBmb3IgYWNjdXJhdGUgcHJlZGljdGlvbiwgZW5zdXJpbmcgYSBtb3JlIGVmZmljaWVudCBhbmQgaW50ZXJwcmV0YWJsZSBtb2RlbC4KCgpBIGZ1bGwgbW9kZWwgaXMgY3JlYXRlZCB0byBwcmVkaWN0IGNob2xlc3Rlcm9sLgoKYGBge3J9Cgojc2FwcGx5KGltcHV0ZWRfbmhhbmVzLCBmdW5jdGlvbih4KSBsZW5ndGgodW5pcXVlKHgpKSkKCiNoZWFkKGltcHV0ZWRfbmhhbmVzLCAyNSkKCgojaGVhZChpbXB1dGVkX25oYW5lcykKCgptb2RlbF9mdWxsIDwtIGxtKGNob2xlc3Ryb2wgfiBhZ2UgKyByYWNlICsgQk1JICsgaGVpZ2h0ICsgYm9keS53ZWlnaHQgKyAKICAgICAgICAgICAgICAgICAgaGJwICsgYXZnLmRicCArIGF2Zy5zYnAgKyBvYmVzZSwgCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBpbXB1dGVkX25oYW5lcykKCiMgU3VtbWFyeSBvZiB0aGUgZnVsbCBtb2RlbAojc3VtbWFyeShtb2RlbF9mdWxsKQoKIyBUaWR5IHRoZSBtb2RlbCBzdW1tYXJ5Cm1vZGVsX3N1bW1hcnkgPC0gdGlkeShtb2RlbF9mdWxsKQoKIyBDYWxjdWxhdGUgTWVhbiBTcXVhcmVkIEVycm9yIChNU0UpCm1zZSA8LSBtZWFuKG1vZGVsX2Z1bGwkcmVzaWR1YWxzXjIpCgojIENhbGN1bGF0ZSBSLXNxdWFyZWQKcjIgPC0gc3VtbWFyeShtb2RlbF9mdWxsKSRyLnNxdWFyZWQKCiMgQ3JlYXRlIGEgZGF0YSBmcmFtZSBmb3IgTVNFIGFuZCBSLXNxdWFyZWQKbWV0cmljc19kZiA8LSBkYXRhLmZyYW1lKFN0YXRpc3RpYyA9IGMoIk1lYW4gU3F1YXJlZCBFcnJvciIsICJSLXNxdWFyZWQiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBWYWx1ZSA9IGMobXNlLCByMikpCgojIFByaW50IHRoZSBtb2RlbCBzdW1tYXJ5IHVzaW5nIGthYmxlCmthYmxlKG1vZGVsX3N1bW1hcnksIGRpZ2l0cyA9IDMsIGNhcHRpb24gPSAiUmVncmVzc2lvbiBNb2RlbCBTdW1tYXJ5IikKCiMgUHJpbnQgTVNFIGFuZCBSLXNxdWFyZWQgdXNpbmcga2FibGUKa2FibGUobWV0cmljc19kZiwgZGlnaXRzID0gMywgY2FwdGlvbiA9ICJNb2RlbCBQZXJmb3JtYW5jZSBNZXRyaWNzIikKCmBgYAoKU3RlcHdpc2UgbW9kZWwgc2VsZWN0aW9uIGlzIGNvbmR1Y3RlZCB0byByZXRhaW4gc2lnbmlmaWNhbnQgcHJlZGljdG9ycy4gU2VsZWN0aW9uIHByb2Nlc3NlcyBiYXNlZCBvbiBBSUMgYW5kIEJJQyBhcmUgY29uZHVjdGVkLiAKCmBgYHtyfQojIFN0ZXB3aXNlIG1vZGVsIHNlbGVjdGlvbiBiYXNlZCBvbiBBSUMKbW9kZWxfc3RlcHdpc2VfQUlDIDwtIHN0ZXAobW9kZWxfZnVsbCwgZGlyZWN0aW9uID0gImJvdGgiLCB0cmFjZSA9IDApCgojIFN0ZXB3aXNlIG1vZGVsIHNlbGVjdGlvbiBiYXNlZCBvbiBCSUMKbW9kZWxfc3RlcHdpc2VfQklDIDwtIHN0ZXAobW9kZWxfZnVsbCwgZGlyZWN0aW9uID0gImJvdGgiLCBrID0gbG9nKG5yb3coaW1wdXRlZF9uaGFuZXMpKSwgdHJhY2UgPSAwKQoKCiMgVGlkeSB0aGUgc3VtbWFyaWVzIGZvciBib3RoIG1vZGVscwpzdGVwd2lzZV9BSUNfc3VtbWFyeSA8LSB0aWR5KG1vZGVsX3N0ZXB3aXNlX0FJQykKc3RlcHdpc2VfQklDX3N1bW1hcnkgPC0gdGlkeShtb2RlbF9zdGVwd2lzZV9CSUMpCgojIENvbXB1dGUgTVNFIGZvciBib3RoIG1vZGVscwptc2VfQUlDIDwtIG1lYW4obW9kZWxfc3RlcHdpc2VfQUlDJHJlc2lkdWFsc14yKQptc2VfQklDIDwtIG1lYW4obW9kZWxfc3RlcHdpc2VfQklDJHJlc2lkdWFsc14yKQoKIyBDb21wdXRlIFItc3F1YXJlZCBmb3IgYm90aCBtb2RlbHMKcjJfQUlDIDwtIHN1bW1hcnkobW9kZWxfc3RlcHdpc2VfQUlDKSRyLnNxdWFyZWQKcjJfQklDIDwtIHN1bW1hcnkobW9kZWxfc3RlcHdpc2VfQklDKSRyLnNxdWFyZWQKCiMgQ3JlYXRlIGRhdGEgZnJhbWVzIGZvciBNU0UgYW5kIFItc3F1YXJlZAptZXRyaWNzX0FJQ19kZiA8LSBkYXRhLmZyYW1lKFN0YXRpc3RpYyA9IGMoIk1lYW4gU3F1YXJlZCBFcnJvciIsICJSLXNxdWFyZWQiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVmFsdWUgPSBjKG1zZV9BSUMsIHIyX0FJQykpCgptZXRyaWNzX0JJQ19kZiA8LSBkYXRhLmZyYW1lKFN0YXRpc3RpYyA9IGMoIk1lYW4gU3F1YXJlZCBFcnJvciIsICJSLXNxdWFyZWQiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVmFsdWUgPSBjKG1zZV9CSUMsIHIyX0JJQykpCgojIFByaW50IHRoZSBzdGVwd2lzZSBBSUMgbW9kZWwgc3VtbWFyeQprYWJsZShzdGVwd2lzZV9BSUNfc3VtbWFyeSwgZGlnaXRzID0gMywgY2FwdGlvbiA9ICJTdGVwd2lzZSBBSUMgUmVncmVzc2lvbiBNb2RlbCBTdW1tYXJ5IikKCiMgUHJpbnQgcGVyZm9ybWFuY2UgbWV0cmljcyBmb3IgQUlDIG1vZGVsCmthYmxlKG1ldHJpY3NfQUlDX2RmLCBkaWdpdHMgPSAzLCBjYXB0aW9uID0gIk1vZGVsIFBlcmZvcm1hbmNlIE1ldHJpY3MgKEFJQykiKQoKIyBQcmludCB0aGUgc3RlcHdpc2UgQklDIG1vZGVsIHN1bW1hcnkKa2FibGUoc3RlcHdpc2VfQklDX3N1bW1hcnksIGRpZ2l0cyA9IDMsIGNhcHRpb24gPSAiU3RlcHdpc2UgQklDIFJlZ3Jlc3Npb24gTW9kZWwgU3VtbWFyeSIpCgojIFByaW50IHBlcmZvcm1hbmNlIG1ldHJpY3MgZm9yIEJJQyBtb2RlbAprYWJsZShtZXRyaWNzX0JJQ19kZiwgZGlnaXRzID0gMywgY2FwdGlvbiA9ICJNb2RlbCBQZXJmb3JtYW5jZSBNZXRyaWNzIChCSUMpIikKYGBgCgoKCmBgYHtyfQojIENoZWNrIFItc3F1YXJlZCB2YWx1ZQpzdW1tYXJ5KG1vZGVsX3N0ZXB3aXNlX0FJQykkci5zcXVhcmVkCnN1bW1hcnkobW9kZWxfc3RlcHdpc2VfQklDKSRyLnNxdWFyZWQKCgpgYGAKCkJvdGggQUlDIGFuZCBCSUMgc3RlcHdpc2UgbW9kZWwgc2VsZWN0aW9uIHByb2Nlc3NlcyBoYXZlIHNpbWlsYXIgUiBzcXVhcmVkIHZhbHVlcy4gVGhlIEJJQyBzdGVwd2lzZSBtb2RlbCBpcyBwYXJzaW1vbmlvdXMuIFRoaXMgbW9kZWwgc2VsZWN0cyBhZ2UsIGhlaWdodCwgYm9keSB3ZWlnaHQsIGFuZCBhdmVyYWdlIGRpYXN0b2xpYyBibG9vZCBwcmVzc3VyZSBhcyBwcmVkaWN0b3JzIGZvciBjaG9sZXN0ZXJvbC4gCgoKClJlZ3VsYXJpemF0aW9uLWJhc2VkIHNlbGVjdGlvbiB0ZWNobmlxdWVzIGFyZSB1c2VmdWwgZm9yIGltcHJvdmluZyBtb2RlbCBwZXJmb3JtYW5jZSBhbmQgcHJldmVudGluZyBvdmVyZml0dGluZywgZXNwZWNpYWxseSB3aGVuIHlvdSBoYXZlIG1hbnkgcHJlZGljdG9ycy4gVHdvIGNvbW1vbiByZWd1bGFyaXphdGlvbiBtZXRob2RzIGFyZSBSaWRnZSByZWdyZXNzaW9uIGFuZCBMYXNzbyByZWdyZXNzaW9uLgoKYGBge3J9CgojIEV4dHJhY3QgdGhlIHJlc3BvbnNlIGFuZCBwcmVkaWN0b3JzCnkgPC0gaW1wdXRlZF9uaGFuZXMkY2hvbGVzdHJvbCAgIyBSZXNwb25zZSB2YXJpYWJsZQpYIDwtIGFzLm1hdHJpeChpbXB1dGVkX25oYW5lc1ssIGMoImFnZSIsICJCTUkiLCAiaGVpZ2h0IiwgImJvZHkud2VpZ2h0IiwgImF2Zy5kYnAiLCAiYXZnLnNicCIpXSkKCiMgT3B0aW9uYWw6IFNjYWxlIHByZWRpY3RvcnMgKHJlY29tbWVuZGVkIGZvciBSaWRnZSBhbmQgTGFzc28pClhfc2NhbGVkIDwtIHNjYWxlKFgpCgojIEZpdCBSaWRnZSBhbmQgTGFzc28gbW9kZWxzCnJpZGdlX21vZGVsIDwtIGdsbW5ldChYX3NjYWxlZCwgeSwgYWxwaGEgPSAwKSAgIyBSaWRnZSBSZWdyZXNzaW9uIChhbHBoYSA9IDApCmxhc3NvX21vZGVsIDwtIGdsbW5ldChYX3NjYWxlZCwgeSwgYWxwaGEgPSAxKSAgIyBMYXNzbyBSZWdyZXNzaW9uIChhbHBoYSA9IDEpCgojIFJpZGdlIGNyb3NzLXZhbGlkYXRpb24KY3ZfcmlkZ2UgPC0gY3YuZ2xtbmV0KFhfc2NhbGVkLCB5LCBhbHBoYSA9IDApCmJlc3RfbGFtYmRhX3JpZGdlIDwtIGN2X3JpZGdlJGxhbWJkYS5taW4KCiMgTGFzc28gY3Jvc3MtdmFsaWRhdGlvbgpjdl9sYXNzbyA8LSBjdi5nbG1uZXQoWF9zY2FsZWQsIHksIGFscGhhID0gMSkKYmVzdF9sYW1iZGFfbGFzc28gPC0gY3ZfbGFzc28kbGFtYmRhLm1pbgoKIyBFeHRyYWN0IGNvZWZmaWNpZW50cyBmb3IgUmlkZ2UgYW5kIExhc3NvIGF0IG9wdGltYWwgbGFtYmRhCnJpZGdlX2NvZWZmaWNpZW50cyA8LSBhcy5kYXRhLmZyYW1lKGFzLm1hdHJpeChjb2VmKGN2X3JpZGdlLCBzID0gImxhbWJkYS5taW4iKSkpCmNvbG5hbWVzKHJpZGdlX2NvZWZmaWNpZW50cykgPC0gYygiQ29lZmZpY2llbnQiKQpyaWRnZV9jb2VmZmljaWVudHMkUHJlZGljdG9yIDwtIHJvd25hbWVzKHJpZGdlX2NvZWZmaWNpZW50cykKCmxhc3NvX2NvZWZmaWNpZW50cyA8LSBhcy5kYXRhLmZyYW1lKGFzLm1hdHJpeChjb2VmKGN2X2xhc3NvLCBzID0gImxhbWJkYS5taW4iKSkpCmNvbG5hbWVzKGxhc3NvX2NvZWZmaWNpZW50cykgPC0gYygiQ29lZmZpY2llbnQiKQpsYXNzb19jb2VmZmljaWVudHMkUHJlZGljdG9yIDwtIHJvd25hbWVzKGxhc3NvX2NvZWZmaWNpZW50cykKCiMgUHJlZGljdGlvbnMgZm9yIFJpZGdlCnByZWRfcmlkZ2UgPC0gcHJlZGljdChjdl9yaWRnZSwgWF9zY2FsZWQsIHMgPSAibGFtYmRhLm1pbiIpCgojIFByZWRpY3Rpb25zIGZvciBMYXNzbwpwcmVkX2xhc3NvIDwtIHByZWRpY3QoY3ZfbGFzc28sIFhfc2NhbGVkLCBzID0gImxhbWJkYS5taW4iKQoKIyBDYWxjdWxhdGUgUk1TRSBmb3IgUmlkZ2UKcm1zZV9yaWRnZSA8LSBzcXJ0KG1lYW4oKHByZWRfcmlkZ2UgLSB5KV4yKSkKCiMgQ2FsY3VsYXRlIFJNU0UgZm9yIExhc3NvCnJtc2VfbGFzc28gPC0gc3FydChtZWFuKChwcmVkX2xhc3NvIC0geSleMikpCgojIENhbGN1bGF0ZSBSwrIgZm9yIFJpZGdlCnJzc19yaWRnZSA8LSBzdW0oKHByZWRfcmlkZ2UgLSB5KV4yKSAgIyBSZXNpZHVhbCBTdW0gb2YgU3F1YXJlcwp0c3NfcmlkZ2UgPC0gc3VtKCh5IC0gbWVhbih5KSleMikgICAgIyBUb3RhbCBTdW0gb2YgU3F1YXJlcwpyMl9yaWRnZSA8LSAxIC0gcnNzX3JpZGdlIC8gdHNzX3JpZGdlCgojIENhbGN1bGF0ZSBSwrIgZm9yIExhc3NvCnJzc19sYXNzbyA8LSBzdW0oKHByZWRfbGFzc28gLSB5KV4yKQp0c3NfbGFzc28gPC0gc3VtKCh5IC0gbWVhbih5KSleMikKcjJfbGFzc28gPC0gMSAtIHJzc19sYXNzbyAvIHRzc19sYXNzbwoKIyBDcmVhdGUgYSBkYXRhIGZyYW1lIGZvciBSTVNFIGFuZCBSwrIKbWV0cmljc19kZiA8LSBkYXRhLmZyYW1lKAogIE1vZGVsID0gYygiUmlkZ2UiLCAiTGFzc28iKSwKICBSTVNFID0gYyhybXNlX3JpZGdlLCBybXNlX2xhc3NvKSwKICBSMiA9IGMocjJfcmlkZ2UsIHIyX2xhc3NvKQopCgojIFByaW50IFJpZGdlIGNvZWZmaWNpZW50cyB1c2luZyBrYWJsZQprYWJsZShyaWRnZV9jb2VmZmljaWVudHMsIGRpZ2l0cyA9IDMsIGNhcHRpb24gPSAiUmlkZ2UgUmVncmVzc2lvbiBDb2VmZmljaWVudHMiKQoKIyBQcmludCBMYXNzbyBjb2VmZmljaWVudHMgdXNpbmcga2FibGUKa2FibGUobGFzc29fY29lZmZpY2llbnRzLCBkaWdpdHMgPSAzLCBjYXB0aW9uID0gIkxhc3NvIFJlZ3Jlc3Npb24gQ29lZmZpY2llbnRzIikKCiMgUHJpbnQgUk1TRSBhbmQgUsKyIHZhbHVlcyB1c2luZyBrYWJsZQprYWJsZShtZXRyaWNzX2RmLCBkaWdpdHMgPSAzLCBjYXB0aW9uID0gIk1vZGVsIFBlcmZvcm1hbmNlIE1ldHJpY3MgKFJNU0UgJiBSwrIpIikKYGBgCgoKVGhlIFJpZGdlIGFuZCBMYXNzbyBtZXRob2QgYm90aCBoYWQgc2ltaWxhciBSIHNxdWFyZWQgdmFsdWVzLiBUaGVyZWZvcmUsIGJvdGggbW9kZWxzIGFyZSByZWNvbW1lbmRlZC4gCgojIExJTkVBUiBSRUdSRVNTSU9OCgpJbiB0aGlzIHJlZ3Jlc3Npb24gYW5hbHlzaXMgb2YgdGhlIE5IQU5FUyBkYXRhc2V0LCB0aHJlZSBtb2RlbHMgYXJlIGRldmVsb3BlZCB1c2luZyBjcm9zcyB2YWxpZGF0aW9uIHRvIHByZWRpY3QgdGhlIG91dGNvbWUgdmFyaWFibGUgY2hvbGVzdGVyb2w6IGEgZnVsbCBtb2RlbCBpbmNsdWRpbmcgYWxsIHNlbGVjdGVkIHByZWRpY3RvcnMsIGEgc3RlcHdpc2UgQklDIG1vZGVsIGZvciB2YXJpYWJsZSBzZWxlY3Rpb24sIGFuZCBhIFJpZGdlIHJlZ3Jlc3Npb24gbW9kZWwgdG8gYWRkcmVzcyBtdWx0aWNvbGxpbmVhcml0eS4gRWFjaCBtb2RlbCB3YXMgZXZhbHVhdGVkIGJhc2VkIG9uIGl0cyBwcmVkaWN0aXZlIHBlcmZvcm1hbmNlLCB3aXRoIE1lYW4gU3F1YXJlZCBFcnJvciAoTVNFKSBhbmQgUi1zcXVhcmVkIChSXjIpIHVzZWQgYXMga2V5IGNvbXBhcmlzb24gbWV0cmljcy4gQnkgYW5hbHl6aW5nIHRoZXNlIG1vZGVscywgdGhlIGFpbSBpcyB0byBkZXRlcm1pbmUgdGhlIG1vc3QgYWNjdXJhdGUgYW5kIGVmZmljaWVudCBhcHByb2FjaCBmb3IgbW9kZWxpbmcgdGhlIGRhdGEgd2hpbGUgYmFsYW5jaW5nIGNvbXBsZXhpdHkgYW5kIHByZWRpY3RpdmUgcG93ZXIuCgpgYGB7cn0KCnNldC5zZWVkKDQyKQp0cmFpbl9jb250cm9sIDwtIHRyYWluQ29udHJvbChtZXRob2QgPSAiY3YiLCBudW1iZXIgPSAxMCkKCmBgYAoKCiMjIEZ1bGwgTW9kZWwKClRoZSBmdWxsIG1vZGVsIGluY2x1ZGVzIGFsbCBzZWxlY3RlZCBwcmVkaWN0b3IgdmFyaWFibGVzLCBwcm92aWRpbmcgYSBjb21wcmVoZW5zaXZlIGFwcHJvYWNoIHRvIGVzdGltYXRpbmcgY2hvbGVzdGVyb2wgbGV2ZWxzLiBUbyBhc3Nlc3MgaXRzIHN0YWJpbGl0eSwgd2UgaW1wbGVtZW50IGstZm9sZCBjcm9zcy12YWxpZGF0aW9uLCB3aGljaCBzeXN0ZW1hdGljYWxseSBwYXJ0aXRpb25zIHRoZSBkYXRhc2V0IGludG8gbXVsdGlwbGUgdHJhaW5pbmcgYW5kIHZhbGlkYXRpb24gc3Vic2V0cy4gVGhpcyBhcHByb2FjaCBtaXRpZ2F0ZXMgdGhlIHJpc2sgb2Ygb3ZlcmZpdHRpbmcgYnkgdGVzdGluZyB0aGUgbW9kZWzigJlzIHBlcmZvcm1hbmNlIG9uIHVuc2VlbiBkYXRhLCB5aWVsZGluZyBhIHJvYnVzdCBlc3RpbWF0ZSBvZiBwcmVkaWN0aW9uIGVycm9yLiBUaGUgbW9kZWzigJlzIGVmZmVjdGl2ZW5lc3MgaXMgcXVhbnRpZmllZCB1c2luZyB0aGUgTWVhbiBTcXVhcmVkIEVycm9yIChNU0UpLCB3aGljaCBtZWFzdXJlcyB0aGUgYXZlcmFnZSBzcXVhcmVkIGRpZmZlcmVuY2UgYmV0d2VlbiBvYnNlcnZlZCBhbmQgcHJlZGljdGVkIGNob2xlc3Rlcm9sIHZhbHVlcy4gQnkgZW1wbG95aW5nIGNyb3NzLXZhbGlkYXRpb24sIHdlIGVuc3VyZSB0aGF0IHRoZSBmdWxsIG1vZGVsIGlzIGV2YWx1YXRlZCByaWdvcm91c2x5LCBwcm92aWRpbmcgaW5zaWdodHMgaW50byBpdHMgYWNjdXJhY3kgYW5kIHJlbGlhYmlsaXR5IGluIHJlYWwtd29ybGQgYXBwbGljYXRpb25zLgoKCmBgYHtyfQoKIyBTZXQgdXAgMTAtZm9sZCBjcm9zcy12YWxpZGF0aW9uCnRyYWluX2NvbnRyb2wgPC0gdHJhaW5Db250cm9sKG1ldGhvZCA9ICJjdiIsIG51bWJlciA9IDEwKSAgIyAxMC1mb2xkIENWCgojIEZpdCB0aGUgZnVsbCBtb2RlbApmdWxsX21vZGVsIDwtIHRyYWluKGNob2xlc3Ryb2wgfiBhZ2UgKyByYWNlICsgbG9nX0JNSSArIGhlaWdodCArIGxvZ19ib2R5LndlaWdodCArIAogICAgICAgICAgICAgICAgICAgIGhicCArIGF2Zy5kYnAgKyBsb2dfYXZnLnNicCArIG9iZXNlLCAKICAgICAgICAgICAgICAgICAgICBkYXRhID0gaW1wdXRlZF9uaGFuZXMsIAogICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJsbSIsIAogICAgICAgICAgICAgICAgICAgIHRyQ29udHJvbCA9IHRyYWluX2NvbnRyb2wpCgojIEV4dHJhY3QgY29lZmZpY2llbnRzIGZyb20gdGhlIGZpbmFsIG1vZGVsCmNvZWZmX3RhYmxlIDwtIHN1bW1hcnkoZnVsbF9tb2RlbCRmaW5hbE1vZGVsKSRjb2VmZmljaWVudHMgJT4lCiAgYXMuZGF0YS5mcmFtZSgpICU+JQogIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAiUHJlZGljdG9yIikgICMgQ29udmVydCByb3cgbmFtZXMgdG8gYSBjb2x1bW4KCiMgQ2FsY3VsYXRlIENyb3NzLVZhbGlkYXRpb24gTVNFCm1zZSA8LSBtZWFuKGZ1bGxfbW9kZWwkcmVzYW1wbGUkUk1TRV4yKQoKIyBDYWxjdWxhdGUgUsKyIGZyb20gdGhlIGZpbmFsIG1vZGVsCnIyIDwtIHN1bW1hcnkoZnVsbF9tb2RlbCRmaW5hbE1vZGVsKSRyLnNxdWFyZWQKCiMgQ3JlYXRlIGEgZGF0YSBmcmFtZSBmb3IgTVNFIGFuZCBSwrIKbWV0cmljc19kZiA8LSBkYXRhLmZyYW1lKAogIFN0YXRpc3RpYyA9IGMoIk1lYW4gU3F1YXJlZCBFcnJvciIsICJSLXNxdWFyZWQiKSwKICBWYWx1ZSA9IGMobXNlLCByMikKKQoKIyBQcmludCB0aGUgY29lZmZpY2llbnRzIHVzaW5nIGthYmxlCmthYmxlKGNvZWZmX3RhYmxlLCBkaWdpdHMgPSA0LCBjYXB0aW9uID0gIlJlZ3Jlc3Npb24gTW9kZWwgQ29lZmZpY2llbnRzIiwgZm9ybWF0ID0gIm1hcmtkb3duIikKCiMgUHJpbnQgTVNFIGFuZCBSwrIgdXNpbmcga2FibGUKa2FibGUobWV0cmljc19kZiwgZGlnaXRzID0gNCwgY2FwdGlvbiA9ICJNb2RlbCBQZXJmb3JtYW5jZSBNZXRyaWNzIChNU0UgJiBSwrIpIiwgZm9ybWF0ID0gIm1hcmtkb3duIikKYGBgCgoKCiMjIFN0ZXB3aXNlIEJJQwoKSW4gdGhpcyBhbmFseXNpcywgYSBTdGVwd2lzZSBCSUMgcmVncmVzc2lvbiBtb2RlbCBpcyBpbXBsZW1lbnRlZCB0byBpZGVudGlmeSB0aGUgbW9zdCBwYXJzaW1vbmlvdXMgc3Vic2V0IG9mIHByZWRpY3RvcnMgZm9yIGVzdGltYXRpbmcgY2hvbGVzdGVyb2wgbGV2ZWxzLiBUaGUgU3RlcHdpc2UgQklDIGFwcHJvYWNoIHNlbGVjdHMgdmFyaWFibGVzIGJ5IG1pbmltaXppbmcgdGhlIEJheWVzaWFuIEluZm9ybWF0aW9uIENyaXRlcmlvbiAoQklDKSwgd2hpY2ggcGVuYWxpemVzIG1vZGVsIGNvbXBsZXhpdHkgdG8gcHJldmVudCBvdmVyZml0dGluZy4gVG8gYXNzZXNzIHRoZSBtb2RlbOKAmXMgZ2VuZXJhbGl6YWJpbGl0eSwgd2UgZW1wbG95IGNyb3NzLXZhbGlkYXRpb24gYnkgc3BsaXR0aW5nIHRoZSBkYXRhc2V0IGludG8gdHJhaW5pbmcgYW5kIHRlc3Rpbmcgc3Vic2V0cy4gVGhlIG1vZGVsIGlzIHRyYWluZWQgb24gdGhlIHRyYWluaW5nIGRhdGEsIGFuZCBwcmVkaWN0aW9ucyBhcmUgbWFkZSBvbiB0aGUgdGVzdCBkYXRhIHRvIGNvbXB1dGUgdGhlIE1lYW4gU3F1YXJlZCBFcnJvciAoTVNFKSBhcyBhIG1lYXN1cmUgb2YgbW9kZWwgcGVyZm9ybWFuY2UuIEFkZGl0aW9uYWxseSwgdGhlIGVzdGltYXRlZCByZWdyZXNzaW9uIGNvZWZmaWNpZW50cyBpbiBhIHN0cnVjdHVyZWQgdGFibGUgZm9yIGNsYXJpdHkgYW5kIGludGVycHJldGF0aW9uLiBUaGlzIGFwcHJvYWNoIGVuc3VyZXMgYW4gb3B0aW1hbCBiYWxhbmNlIGJldHdlZW4gbW9kZWwgY29tcGxleGl0eSBhbmQgcHJlZGljdGl2ZSBhY2N1cmFjeSB3aGlsZSB2YWxpZGF0aW5nIHRoZSBtb2RlbOKAmXMgcm9idXN0bmVzcy4KCmBgYHtyfQoKc3RlcHdpc2VfYmljX21vZGVsIDwtIGZ1bmN0aW9uKHRyYWluX2RhdGEsIHRlc3RfZGF0YSkgewogICMgRml0IGluaXRpYWwgZnVsbCBtb2RlbAogIGZ1bGxfbW9kZWwyIDwtIGxtKGNob2xlc3Ryb2wgfiBhZ2UgKyBoZWlnaHQgKyBsb2dfYm9keS53ZWlnaHQgKyBhdmcuZGJwLCBkYXRhID0gdHJhaW5fZGF0YSkKICAKICAjIFBlcmZvcm0gc3RlcHdpc2Ugc2VsZWN0aW9uIHVzaW5nIEJJQwogIG1vZGVsX3N0ZXB3aXNlX0JJQyA8LSBzdGVwQUlDKGZ1bGxfbW9kZWwyLCBkaXJlY3Rpb24gPSAiYm90aCIsIGsgPSBsb2cobnJvdyh0cmFpbl9kYXRhKSksIHRyYWNlID0gRkFMU0UpCiAgCiAgIyBFeHRyYWN0IGNvZWZmaWNpZW50cwogIGNvZWZmX3RhYmxlIDwtIHN1bW1hcnkobW9kZWxfc3RlcHdpc2VfQklDKSRjb2VmZmljaWVudHMgJT4lCiAgICBhcy5kYXRhLmZyYW1lKCkgJT4lCiAgICByb3duYW1lc190b19jb2x1bW4odmFyID0gIlByZWRpY3RvciIpICAjIENvbnZlcnQgcm93IG5hbWVzIHRvIGEgY29sdW1uCgogICMgUHJpbnQgY29lZmZpY2llbnRzIHVzaW5nIGthYmxlCiAgcHJpbnQoa2FibGUoY29lZmZfdGFibGUsIGRpZ2l0cyA9IDQsIGNhcHRpb24gPSAiU3RlcHdpc2UgQklDIE1vZGVsIENvZWZmaWNpZW50cyIsIGZvcm1hdCA9ICJtYXJrZG93biIpKQoKICAjIFByZWRpY3Qgb24gdGVzdCBkYXRhCiAgcHJlZGljdGlvbnMgPC0gcHJlZGljdChtb2RlbF9zdGVwd2lzZV9CSUMsIG5ld2RhdGEgPSB0ZXN0X2RhdGEpCiAgCiAgIyBDb21wdXRlIE1lYW4gU3F1YXJlZCBFcnJvciAoTVNFKQogIG1zZSA8LSBtZWFuKCh0ZXN0X2RhdGEkY2hvbGVzdHJvbCAtIHByZWRpY3Rpb25zKV4yKQoKICAjIENvbXB1dGUgUsKyCiAgcnNzIDwtIHN1bSgodGVzdF9kYXRhJGNob2xlc3Ryb2wgLSBwcmVkaWN0aW9ucyleMikgICMgUmVzaWR1YWwgU3VtIG9mIFNxdWFyZXMKICB0c3MgPC0gc3VtKCh0ZXN0X2RhdGEkY2hvbGVzdHJvbCAtIG1lYW4odGVzdF9kYXRhJGNob2xlc3Ryb2wpKV4yKSAgIyBUb3RhbCBTdW0gb2YgU3F1YXJlcwogIHIyIDwtIDEgLSByc3MvdHNzICAjIFItc3F1YXJlZAogIAogICMgQ3JlYXRlIGEgZGF0YSBmcmFtZSBmb3IgTVNFIGFuZCBSwrIKICBtZXRyaWNzX2RmIDwtIGRhdGEuZnJhbWUoCiAgICBTdGF0aXN0aWMgPSBjKCJNZWFuIFNxdWFyZWQgRXJyb3IiLCAiUi1zcXVhcmVkIiksCiAgICBWYWx1ZSA9IGMobXNlLCByMikKICApCgogICMgUHJpbnQgTVNFIGFuZCBSwrIgdXNpbmcga2FibGUKICBwcmludChrYWJsZShtZXRyaWNzX2RmLCBkaWdpdHMgPSA0LCBjYXB0aW9uID0gIlN0ZXB3aXNlIEJJQyBNb2RlbCBQZXJmb3JtYW5jZSBNZXRyaWNzIChNU0UgJiBSwrIpIiwgZm9ybWF0ID0gIm1hcmtkb3duIikpCgogIHJldHVybihsaXN0KG1vZGVsID0gbW9kZWxfc3RlcHdpc2VfQklDLCBtc2UgPSBtc2UsIHIyID0gcjIpKSAgIyBSZXR1cm4gdGhlIG1vZGVsLCBNU0UsIGFuZCBSwrIKfQoKIyBFeGFtcGxlIHVzYWdlIChBc3N1bWluZyB5b3UgaGF2ZSBhIGRhdGFzZXQgc3BsaXQgaW50byB0cmFpbl9kYXRhIGFuZCB0ZXN0X2RhdGEpCnNldC5zZWVkKDEyMykKdHJhaW5faW5kZXggPC0gY3JlYXRlRGF0YVBhcnRpdGlvbihpbXB1dGVkX25oYW5lcyRjaG9sZXN0cm9sLCBwID0gMC44LCBsaXN0ID0gRkFMU0UpCnRyYWluX2RhdGEgPC0gaW1wdXRlZF9uaGFuZXNbdHJhaW5faW5kZXgsIF0KdGVzdF9kYXRhIDwtIGltcHV0ZWRfbmhhbmVzWy10cmFpbl9pbmRleCwgXQoKIyBSdW4gdGhlIGZ1bmN0aW9uCnN0ZXB3aXNlX3Jlc3VsdHMgPC0gc3RlcHdpc2VfYmljX21vZGVsKHRyYWluX2RhdGEsIHRlc3RfZGF0YSkKCgpgYGAKCgojIyBSaWRnZSBSZWdyZXNzaW9uCgpSaWRnZSByZWdyZXNzaW9uIGlzIGFwcGxpZWQgdG8gdGhlIE5IQU5FUyBkYXRhc2V0IHRvIGFkZHJlc3MgbXVsdGljb2xsaW5lYXJpdHkgYW1vbmcgcHJlZGljdG9yIHZhcmlhYmxlcyB3aGlsZSBtYWludGFpbmluZyBtb2RlbCBzdGFiaWxpdHkuIEJ5IGltcG9zaW5nIGEgcGVuYWx0eSBvbiBsYXJnZSBjb2VmZmljaWVudHMgdGhyb3VnaCBMMiByZWd1bGFyaXphdGlvbiwgUmlkZ2UgcmVncmVzc2lvbiBwcmV2ZW50cyBvdmVyZml0dGluZyBhbmQgaW1wcm92ZXMgZ2VuZXJhbGl6YXRpb24uIFRoZSBtb2RlbCB3YXMgZXZhbHVhdGVkIHVzaW5nIGNyb3NzLXZhbGlkYXRpb24sIGFuZCBpdHMgcGVyZm9ybWFuY2Ugd2FzIGNvbXBhcmVkIHRvIG90aGVyIHJlZ3Jlc3Npb24gYXBwcm9hY2hlcyBiYXNlZCBvbiBNZWFuIFNxdWFyZWQgRXJyb3IgKE1TRSkgYW5kIFLCsi4KCmBgYHtyfQoKIyBEZWZpbmUgcHJlZGljdG9yIG1hdHJpeCAoWCkgYW5kIHJlc3BvbnNlIHZhcmlhYmxlICh5KQpYIDwtIGFzLm1hdHJpeChpbXB1dGVkX25oYW5lc1ssIGMoImFnZSIsICJsb2dfQk1JIiwgImhlaWdodCIsICJsb2dfYm9keS53ZWlnaHQiLCAiYXZnLmRicCIsICJsb2dfYXZnLnNicCIpXSkKeSA8LSBpbXB1dGVkX25oYW5lcyRjaG9sZXN0cm9sCgpzZXQuc2VlZCgxMjMpICAjIEZvciByZXByb2R1Y2liaWxpdHkKCiMgRGVmaW5lIHRyYWluaW5nIGNvbnRyb2wgd2l0aCAxMC1mb2xkIGNyb3NzLXZhbGlkYXRpb24KdHJhaW5fY29udHJvbCA8LSB0cmFpbkNvbnRyb2wobWV0aG9kID0gImN2IiwgbnVtYmVyID0gMTApCgojIFRyYWluIFJpZGdlIFJlZ3Jlc3Npb24gTW9kZWwKcmlkZ2VfbW9kZWwgPC0gdHJhaW4oCiAgeCA9IFgsIHkgPSB5LAogIG1ldGhvZCA9ICJnbG1uZXQiLAogIHRyQ29udHJvbCA9IHRyYWluX2NvbnRyb2wsCiAgdHVuZUdyaWQgPSBleHBhbmQuZ3JpZChhbHBoYSA9IDAsIGxhbWJkYSA9IDEwXnNlcSgtMywgMywgbGVuZ3RoID0gMTAwKSkgICMgUmlkZ2U6IGFscGhhID0gMAopCgojIEJlc3QgbGFtYmRhIHZhbHVlIHNlbGVjdGVkIHZpYSBjcm9zcy12YWxpZGF0aW9uCmJlc3RfbGFtYmRhIDwtIHJpZGdlX21vZGVsJGJlc3RUdW5lJGxhbWJkYQoKIyBQcmVkaWN0IHVzaW5nIGJlc3QgbGFtYmRhCnJpZGdlX3ByZWRpY3Rpb25zIDwtIHByZWRpY3QocmlkZ2VfbW9kZWwsIFgpCgojIENvbXB1dGUgTWVhbiBTcXVhcmVkIEVycm9yIChNU0UpCnJpZGdlX21zZSA8LSBtZWFuKCh5IC0gcmlkZ2VfcHJlZGljdGlvbnMpXjIpCgojIENvbXB1dGUgUsKyCnJzcyA8LSBzdW0oKHkgLSByaWRnZV9wcmVkaWN0aW9ucyleMikgICMgUmVzaWR1YWwgU3VtIG9mIFNxdWFyZXMKdHNzIDwtIHN1bSgoeSAtIG1lYW4oeSkpXjIpICAjIFRvdGFsIFN1bSBvZiBTcXVhcmVzCnJpZGdlX3IyIDwtIDEgLSAocnNzIC8gdHNzKSAgIyBSwrIgY2FsY3VsYXRpb24KCiMgRXh0cmFjdCBjb2VmZmljaWVudHMgZnJvbSB0aGUgZmluYWwgUmlkZ2UgbW9kZWwKY29lZmZpY2llbnRzIDwtIGFzLmRhdGEuZnJhbWUoYXMubWF0cml4KHJpZGdlX21vZGVsJGZpbmFsTW9kZWwkYmV0YSkpICU+JQogIHRpYmJsZTo6cm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJQcmVkaWN0b3IiKSAgIyBDb252ZXJ0IHJvdyBuYW1lcyB0byBhIGNvbHVtbgoKI3ByaW50KGthYmxlKGhlYWQoY29lZmZpY2llbnRzLCAxMCksIGRpZ2l0cyA9IDQsIGNhcHRpb24gPSAiVG9wIDEwIFJpZGdlIFJlZ3Jlc3Npb24gQ29lZmZpY2llbnRzIiwgZm9ybWF0ID0gIm1hcmtkb3duIikpCgoKIyBDcmVhdGUgYSBkYXRhIGZyYW1lIGZvciBNU0UsIFLCsiwgYW5kIEJlc3QgTGFtYmRhCm1ldHJpY3NfZGYgPC0gZGF0YS5mcmFtZSgKICBTdGF0aXN0aWMgPSBjKCJNZWFuIFNxdWFyZWQgRXJyb3IiLCAiUi1zcXVhcmVkIiwgIk9wdGltYWwgTGFtYmRhIiksCiAgVmFsdWUgPSBjKHJpZGdlX21zZSwgcmlkZ2VfcjIsIGJlc3RfbGFtYmRhKQopCgojIFByaW50IG1vZGVsIHBlcmZvcm1hbmNlIG1ldHJpY3MgdXNpbmcga2FibGUoKQpwcmludChrYWJsZShtZXRyaWNzX2RmLCBkaWdpdHMgPSA0LCBjYXB0aW9uID0gIlJpZGdlIFJlZ3Jlc3Npb24gUGVyZm9ybWFuY2UgTWV0cmljcyIsIGZvcm1hdCA9ICJtYXJrZG93biIpKQpgYGAKCgoKIyMgQ29tcGFyaXNvbgoKQWZ0ZXIgcGVyZm9ybWluZyBjcm9zcy12YWxpZGF0aW9uIG9uIHRoZSBOSEFORVNfaW1wdXRlZCBkYXRhc2V0LCB0aGUgcHJlZGljdGl2ZSBwZXJmb3JtYW5jZSBvZiB0aGUgdGhyZSBtb2RlbHMgYXJlIGNvbXBhcmVkLiBUaGUgQklDIG1vZGVsIGhhcyB0aGUgc21hbGxlc3QgTVNFIGFuZCBoaWdoZXN0IFJeMiB2YWx1ZSwgaW5kaWNhdGluZyBhIGJldHRlciBwZXJmb3JtaW5nIHJlZ3Jlc3Npb24gbW9kZWwuIEluLCB0dXJuLCB0aGUgQklDIG1vZGVsIGlzIHJlY29tbWVuZGVkLiAKCgoKCiMgTE9HSVNUSUMgUkVHUkVTU0lPTgoKVGhpcyBhbmFseXNpcyBhcHBsaWVzIGxvZ2lzdGljIHJlZ3Jlc3Npb24gdG8gcHJlZGljdCBjdXJyZW50IHNtb2tpbmcgc3RhdHVzIHVzaW5nIGRhdGEgZnJvbSBOSEFORVMuIEZvdXIgbW9kZWxzIGFyZSBkZXZlbG9wZWQ6IGEgZnVsbCBtb2RlbCBpbmNsdWRpbmcgYWxsIHJlbGV2YW50IHByZWRpY3RvcnMsIGEgc3RlcHdpc2UgQUlDIG1vZGVsIGZvciB2YXJpYWJsZSBzZWxlY3Rpb24sIGEgQklDIG1vZGVsIGZvciBhIG1vcmUgcGFyc2ltb25pb3VzIGFwcHJvYWNoLCBhbmQgYSByZWd1bGFyaXplZCBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsIHVzaW5nIExhc3NvIHRvIHByZXZlbnQgb3ZlcmZpdHRpbmcuIFRoZSBtb2RlbHMgYXJlIGV2YWx1YXRlZCBhbmQgY29tcGFyZWQgdXNpbmcgUmVjZWl2ZXIgT3BlcmF0aW5nIENoYXJhY3RlcmlzdGljIChST0MpIGN1cnZlcyBhbmQgdGhlIEFyZWEgVW5kZXIgdGhlIEN1cnZlIChBVUMpIHRvIGFzc2VzcyB0aGVpciBjbGFzc2lmaWNhdGlvbiBwZXJmb3JtYW5jZSBhbmQgcHJlZGljdGl2ZSBhY2N1cmFjeS4KCiMjIEZ1bGwgTW9kZWwKClRoZSBmaXJzdCBjYW5kaWRhdGUsIGEgZnVsbCBtb2RlbCwgaXMgZml0dGVkIHRvIHByZWRpY3QgY3VycmVudCBzbW9raW5nIHN0YXR1cy4gCgpgYGB7cn0KCiMgRml0IGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwKZnVsbF9tb2RlbCA8LSBnbG0oY3VycmVudC5zbWsgfiBhZ2UgKyByYWNlICsgbG9nX2JvZHkud2VpZ2h0ICsgbG9nX0JNSSArIG9iZXNlICsgCiAgICAgICAgICAgICAgICAgICAgaGVpZ2h0ICsgbG9nX2F2Zy5zYnAgKyBhdmcuZGJwICsgbG9nX2Nob2xlc3Ryb2wgKyBoYnAsIAogICAgICAgICAgICAgICAgICBkYXRhID0gaW1wdXRlZF9uaGFuZXMsIAogICAgICAgICAgICAgICAgICBmYW1pbHkgPSBiaW5vbWlhbCkKCiMgRXh0cmFjdCBjb2VmZmljaWVudHMgZnJvbSB0aGUgbW9kZWwKY29lZmZpY2llbnRzIDwtIHN1bW1hcnkoZnVsbF9tb2RlbCkkY29lZmZpY2llbnRzCgojIENvbnZlcnQgY29lZmZpY2llbnRzIHRvIGEgZGF0YSBmcmFtZSBhbmQgYWRkIHJvdyBuYW1lcyBhcyBhIGNvbHVtbgpjb2VmZl90YWJsZSA8LSBhcy5kYXRhLmZyYW1lKGNvZWZmaWNpZW50cykgJT4lCiAgdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4odmFyID0gIlByZWRpY3RvciIpICAjIENvbnZlcnQgcm93IG5hbWVzIHRvIGEgY29sdW1uCgojIFByaW50IHRoZSBjb2VmZmljaWVudHMgdGFibGUgdXNpbmcga2FibGUKa2FibGUoY29lZmZfdGFibGUsIGRpZ2l0cyA9IDQsIGNhcHRpb24gPSAiTG9naXN0aWMgUmVncmVzc2lvbiBNb2RlbCBDb2VmZmljaWVudHMiLCBmb3JtYXQgPSAibWFya2Rvd24iKQoKCgpgYGAKCkFnZSwgcmFjZSwgYW5kIGF2ZXJhZ2UgZGJwIGFyZSBzaWduaWZpY2FudCBmZWF0dXJlcyBpbiB0aGUgZnVsbCBtb2RlbC4gCgojIyBTdGVwd2lzZSBBSUMgTW9kZWwKClRoZSBzZWNvbmQgbW9kZWwsIHN0ZXB3aXNlIEFJQywgaXMgZml0dGVkIHRvIHByZWRpY3QgY3VycmVudCBzbW9raW5nIHN0YXR1cy4gVGhpcyBtb2RlbCBhdXRvbWF0aWNhbGx5IHNlbGVjdHMgYSBzdWJzZXQgb2YgcHJlZGljdG9ycyB1c2luZyBBSUMtYmFzZWQgc3RlcHdpc2Ugc2VsZWN0aW9uLiAKCmBgYHtyfQoKCiMgRml0IGluaXRpYWwgZnVsbCBtb2RlbApmdWxsX21vZGVsIDwtIGdsbShjdXJyZW50LnNtayB+IGFnZSArIHJhY2UgKyBsb2dfYm9keS53ZWlnaHQgKyBsb2dfQk1JICsgb2Jlc2UgKyAKICAgICAgICAgICAgICAgICAgICBoZWlnaHQgKyBsb2dfYXZnLnNicCArIGF2Zy5kYnAgKyBsb2dfY2hvbGVzdHJvbCArIGhicCwgCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBpbXB1dGVkX25oYW5lcywgCiAgICAgICAgICAgICAgICAgIGZhbWlseSA9IGJpbm9taWFsKQoKIyBQZXJmb3JtIHN0ZXB3aXNlIHNlbGVjdGlvbiB1c2luZyBBSUMKc3RlcHdpc2VfbW9kZWwgPC0gc3RlcEFJQyhmdWxsX21vZGVsLCBkaXJlY3Rpb24gPSAiYm90aCIsIHRyYWNlID0gRkFMU0UpCgojIEV4dHJhY3QgY29lZmZpY2llbnRzIGZyb20gdGhlIHN0ZXB3aXNlIG1vZGVsCmNvZWZmaWNpZW50c19zdGVwd2lzZSA8LSBzdW1tYXJ5KHN0ZXB3aXNlX21vZGVsKSRjb2VmZmljaWVudHMKCiMgQ29udmVydCBjb2VmZmljaWVudHMgdG8gYSBkYXRhIGZyYW1lIGFuZCBhZGQgcm93IG5hbWVzIGFzIGEgY29sdW1uCmNvZWZmX3RhYmxlX3N0ZXB3aXNlIDwtIGFzLmRhdGEuZnJhbWUoY29lZmZpY2llbnRzX3N0ZXB3aXNlKSAlPiUKICB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAiUHJlZGljdG9yIikgICMgQ29udmVydCByb3cgbmFtZXMgdG8gYSBjb2x1bW4KCiMgUHJpbnQgdGhlIGNvZWZmaWNpZW50cyB0YWJsZSB1c2luZyBrYWJsZQprYWJsZShjb2VmZl90YWJsZV9zdGVwd2lzZSwgZGlnaXRzID0gNCwgY2FwdGlvbiA9ICJTdGVwd2lzZSBMb2dpc3RpYyBSZWdyZXNzaW9uIE1vZGVsIENvZWZmaWNpZW50cyIsIGZvcm1hdCA9ICJtYXJrZG93biIpCgoKCmBgYAoKQWxsIGZlYXR1cmVzLCBvdGhlciB0aGFuIG9iZXNlLCBhcmUgc2lnbmlmaWNhbnQgaW4gdGhlIHN0ZXB3aXNlIEFJQyBtb2RlbC4gCgoKIyMgQklDIE1vZGVsCgpUaGUgdGhpcmQgY2FuZGlkYXRlLGEgQklDIG1vZGVsLCBpcyBmaXR0ZWQgdG8gcHJlZGljdCBjdXJyZW50IHNtb2tpbmcgc3RhdHVzLiBUaGlzIG1vZGVsIGZpdHMgYSBtb3JlIHBhcnNpbW9uaW91cyBtb2RlbC4gCgpgYGB7cn0KCiMgRml0IGluaXRpYWwgZnVsbCBtb2RlbApmdWxsX21vZGVsIDwtIGdsbShjdXJyZW50LnNtayB+IGFnZSArIHJhY2UgKyBsb2dfYm9keS53ZWlnaHQgKyBsb2dfQk1JICsgb2Jlc2UgKyAKICAgICAgICAgICAgICAgICAgICBoZWlnaHQgKyBsb2dfYXZnLnNicCArIGF2Zy5kYnAgKyBsb2dfY2hvbGVzdHJvbCArIGhicCwgCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBpbXB1dGVkX25oYW5lcywgCiAgICAgICAgICAgICAgICAgIGZhbWlseSA9IGJpbm9taWFsKQoKIyBQZXJmb3JtIHN0ZXB3aXNlIHNlbGVjdGlvbiB1c2luZyBCSUMgKHVzaW5nIGsgPSBsb2cobnJvdyhpbXB1dGVkX25oYW5lcykpKQpiaWNfbW9kZWwgPC0gc3RlcEFJQyhmdWxsX21vZGVsLCBkaXJlY3Rpb24gPSAiYm90aCIsIGsgPSBsb2cobnJvdyhpbXB1dGVkX25oYW5lcykpLCB0cmFjZSA9IEZBTFNFKQoKIyBFeHRyYWN0IGNvZWZmaWNpZW50cyBmcm9tIHRoZSBCSUMgbW9kZWwKY29lZmZpY2llbnRzX2JpYyA8LSBzdW1tYXJ5KGJpY19tb2RlbCkkY29lZmZpY2llbnRzCgojIENvbnZlcnQgY29lZmZpY2llbnRzIHRvIGEgZGF0YSBmcmFtZSBhbmQgYWRkIHJvdyBuYW1lcyBhcyBhIGNvbHVtbgpjb2VmZl90YWJsZV9iaWMgPC0gYXMuZGF0YS5mcmFtZShjb2VmZmljaWVudHNfYmljKSAlPiUKICB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAiUHJlZGljdG9yIikgICMgQ29udmVydCByb3cgbmFtZXMgdG8gYSBjb2x1bW4KCiMgUHJpbnQgdGhlIGNvZWZmaWNpZW50cyB0YWJsZSB1c2luZyBrYWJsZQprYWJsZShjb2VmZl90YWJsZV9iaWMsIGRpZ2l0cyA9IDQsIGNhcHRpb24gPSAiQklDIFN0ZXB3aXNlIE1vZGVsIENvZWZmaWNpZW50cyIsIGZvcm1hdCA9ICJtYXJrZG93biIpCgoKYGBgCgpBbGwgZmVhdHVyZXMgYXJlIHNpZ25pZmljYW50IGluIHRoZSBCSUMgbW9kZWwuCgoKIyMgUmVndWxhcml6ZWQgTG9naXN0aWMgUmVncmVzc2lvbiBNb2RlbCAoTGFzc28pCgpUaGUgZm91cnRoIGNhbmRpZGF0ZSBtb2RlbCB1c2VzIFJlZ3VsYXJpemVkIExvZ2lzdGljIFJlZ3Jlc3Npb24gKExhc3NvKS4gVGhpcyBtZXRob2Qgc2VsZWN0cyB0aGUgbW9zdCBpbXBvcnRhbnQgcHJlZGljdG9ycy4KCmBgYHtyfQoKIyBEZWZpbmUgcHJlZGljdG9yIG1hdHJpeCAoWCkgYW5kIHJlc3BvbnNlIHZhcmlhYmxlICh5KQp4IDwtIG1vZGVsLm1hdHJpeChjdXJyZW50LnNtayB+IGFnZSArIHJhY2UgKyBsb2dfYm9keS53ZWlnaHQgKyBsb2dfQk1JICsgb2Jlc2UgKyBoZWlnaHQgKyBsb2dfYXZnLnNicCArIGF2Zy5kYnAgKyBsb2dfY2hvbGVzdHJvbCArIGhicCwgCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBpbXB1dGVkX25oYW5lcylbLCAtMV0gICMgRXhjbHVkZSBpbnRlcmNlcHQKeSA8LSBpbXB1dGVkX25oYW5lcyRjdXJyZW50LnNtawoKIyBUcmFpbiB0aGUgTGFzc28gbW9kZWwgdXNpbmcgY3Jvc3MtdmFsaWRhdGlvbgpsYXNzb19tb2RlbCA8LSBjdi5nbG1uZXQoeCwgeSwgZmFtaWx5ID0gImJpbm9taWFsIiwgYWxwaGEgPSAxKQoKCiMgQmVzdCBsYW1iZGEgdmFsdWUgc2VsZWN0ZWQgdmlhIGNyb3NzLXZhbGlkYXRpb24KYmVzdF9sYW1iZGFfbGFzc28gPC0gbGFzc29fbW9kZWwkbGFtYmRhLm1pbgpwcmludChwYXN0ZSgiT3B0aW1hbCBMYW1iZGEgZm9yIExhc3NvOiIsIGJlc3RfbGFtYmRhX2xhc3NvKSkKCiMgRXh0cmFjdCBjb2VmZmljaWVudHMgZnJvbSB0aGUgZmluYWwgTGFzc28gbW9kZWwgYXQgdGhlIG9wdGltYWwgbGFtYmRhCmxhc3NvX2NvZWZmaWNpZW50cyA8LSBjb2VmKGxhc3NvX21vZGVsLCBzID0gImxhbWJkYS5taW4iKQoKIyBDb252ZXJ0IGNvZWZmaWNpZW50cyB0byBhIGRhdGEgZnJhbWUKbGFzc29fY29lZmZpY2llbnRzX2RmIDwtIGFzLmRhdGEuZnJhbWUoYXMubWF0cml4KGxhc3NvX2NvZWZmaWNpZW50cykpCmxhc3NvX2NvZWZmaWNpZW50c19kZiRQcmVkaWN0b3IgPC0gcm93bmFtZXMobGFzc29fY29lZmZpY2llbnRzX2RmKQoKIyBSZW9yZGVyIGNvbHVtbnMgdG8gbWFrZSBwcmVkaWN0b3IgbmFtZXMgdGhlIGZpcnN0IGNvbHVtbgpsYXNzb19jb2VmZmljaWVudHNfZGYgPC0gbGFzc29fY29lZmZpY2llbnRzX2RmICU+JQogIHNlbGVjdChQcmVkaWN0b3IsIGV2ZXJ5dGhpbmcoKSkKCiMgUHJpbnQgdGhlIGNvZWZmaWNpZW50cyB0YWJsZSB1c2luZyBrYWJsZQprYWJsZShsYXNzb19jb2VmZmljaWVudHNfZGYsIGRpZ2l0cyA9IDQsIGNhcHRpb24gPSAiTGFzc28gUmVncmVzc2lvbiBDb2VmZmljaWVudHMiLCBmb3JtYXQgPSAibWFya2Rvd24iKQoKCmBgYAoKCiMjIENvbXBhcmlzb24KCkluIHRoaXMgYW5hbHlzaXMsIGZvdXIgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbHPigJRGdWxsIE1vZGVsLCBTdGVwd2lzZSBBSUMgTW9kZWwsIEJJQyBNb2RlbCwgYW5kIExhc3NvIE1vZGVsIGFyZSBjb21wYXJlZCB1c2luZyBST0MgKFJlY2VpdmVyIE9wZXJhdGluZyBDaGFyYWN0ZXJpc3RpYykgY3VydmVzIGFuZCBBVUMgKEFyZWEgVW5kZXIgdGhlIEN1cnZlKSB0byBhc3Nlc3MgdGhlaXIgcHJlZGljdGl2ZSBwZXJmb3JtYW5jZS4gIFRoZSBvcHRpbWFsIGN1dG9mZiBmb3IgZWFjaCBtb2RlbCB1c2luZyBZb3VkZW7igJlzIEluZGV4IGlzIGRldGVybWluZWQsIHdoaWNoIG1heGltaXplcyB0aGUgYmFsYW5jZSBiZXR3ZWVuIHNlbnNpdGl2aXR5IGFuZCBzcGVjaWZpY2l0eS4gQnkgZXZhbHVhdGluZyB0aGVzZSBtb2RlbHMgdGhyb3VnaCBib3RoIGdyYXBoaWNhbCBhbmQgbnVtZXJpY2FsIG1ldHJpY3MsIGluc2lnaHRzIGlzIGdhaW5lZCBpbnRvIHdoaWNoIG1vZGVsIHByb3ZpZGVzIHRoZSBiZXN0IGNsYXNzaWZpY2F0aW9uIHBlcmZvcm1hbmNlIGZvciBwcmVkaWN0aW5nIHRoZSBvdXRjb21lIHZhcmlhYmxlLgoKYGBge3J9CiMgRnVsbCBNb2RlbApmdWxsX21vZGVsIDwtIGdsbShjdXJyZW50LnNtayB+IGFnZSArIHJhY2UgKyBsb2dfYm9keS53ZWlnaHQgKyBsb2dfQk1JICsgb2Jlc2UgKyBoZWlnaHQgKyBsb2dfYXZnLnNicCArIGF2Zy5kYnAgKyBsb2dfY2hvbGVzdHJvbCArIGhicCwgZGF0YSA9IGltcHV0ZWRfbmhhbmVzLCBmYW1pbHkgPSBiaW5vbWlhbCkKCiMgU3RlcHdpc2UgQUlDIE1vZGVsCnN0ZXB3aXNlX21vZGVsIDwtIHN0ZXBBSUMoZnVsbF9tb2RlbCwgZGlyZWN0aW9uID0gImJvdGgiLCB0cmFjZSA9IEZBTFNFKQoKIyBCSUMgTW9kZWwKYmljX21vZGVsIDwtIHN0ZXBBSUMoZnVsbF9tb2RlbCwgZGlyZWN0aW9uID0gImJvdGgiLCBrID0gbG9nKG5yb3coaW1wdXRlZF9uaGFuZXMpKSwgdHJhY2UgPSBGQUxTRSkKCiMgTGFzc28gTW9kZWwKeCA8LSBtb2RlbC5tYXRyaXgoY3VycmVudC5zbWsgfiBhZ2UgKyByYWNlICsgbG9nX2JvZHkud2VpZ2h0ICsgbG9nX0JNSSArIG9iZXNlICsgaGVpZ2h0ICsgbG9nX2F2Zy5zYnAgKyBhdmcuZGJwICsgbG9nX2Nob2xlc3Ryb2wgKyBoYnAgLCBkYXRhID0gaW1wdXRlZF9uaGFuZXMpWywgLTFdICAjIEV4Y2x1ZGUgaW50ZXJjZXB0CnkgPC0gaW1wdXRlZF9uaGFuZXMkY3VycmVudC5zbWsKbGFzc29fY3YgPC0gY3YuZ2xtbmV0KHgsIHksIGZhbWlseSA9ICJiaW5vbWlhbCIsIGFscGhhID0gMSkKbGFzc29fbW9kZWwgPC0gZ2xtbmV0KHgsIHksIGZhbWlseSA9ICJiaW5vbWlhbCIsIGFscGhhID0gMSwgbGFtYmRhID0gbGFzc29fY3YkbGFtYmRhLm1pbikKCiMgR2V0IHByZWRpY3RlZCBwcm9iYWJpbGl0aWVzCmltcHV0ZWRfbmhhbmVzJGZ1bGxfcHJlZCA8LSBwcmVkaWN0KGZ1bGxfbW9kZWwsIHR5cGUgPSAicmVzcG9uc2UiKQppbXB1dGVkX25oYW5lcyRzdGVwd2lzZV9wcmVkIDwtIHByZWRpY3Qoc3RlcHdpc2VfbW9kZWwsIHR5cGUgPSAicmVzcG9uc2UiKQppbXB1dGVkX25oYW5lcyRiaWNfcHJlZCA8LSBwcmVkaWN0KGJpY19tb2RlbCwgdHlwZSA9ICJyZXNwb25zZSIpCmltcHV0ZWRfbmhhbmVzJGxhc3NvX3ByZWQgPC0gcHJlZGljdChsYXNzb19tb2RlbCwgbmV3eCA9IHgsIHR5cGUgPSAicmVzcG9uc2UiKVssMV0KCiMgQ3JlYXRlIFJPQyBjdXJ2ZXMKZnVsbF9yb2MgPC0gcm9jKGltcHV0ZWRfbmhhbmVzJGN1cnJlbnQuc21rLCBpbXB1dGVkX25oYW5lcyRmdWxsX3ByZWQpCnN0ZXB3aXNlX3JvYyA8LSByb2MoaW1wdXRlZF9uaGFuZXMkY3VycmVudC5zbWssIGltcHV0ZWRfbmhhbmVzJHN0ZXB3aXNlX3ByZWQpCmJpY19yb2MgPC0gcm9jKGltcHV0ZWRfbmhhbmVzJGN1cnJlbnQuc21rLCBpbXB1dGVkX25oYW5lcyRiaWNfcHJlZCkKbGFzc29fcm9jIDwtIHJvYyhpbXB1dGVkX25oYW5lcyRjdXJyZW50LnNtaywgaW1wdXRlZF9uaGFuZXMkbGFzc29fcHJlZCkKCiMgQ2FsY3VsYXRlIG9wdGltYWwgY3V0b2ZmIHVzaW5nIFlvdWRlbidzIEluZGV4Cm9wdGltYWxfY3V0b2ZmX2Z1bGwgPC0gZnVsbF9yb2Mkc3BlY2lmaWNpdGllc1t3aGljaC5tYXgoZnVsbF9yb2Mkc2Vuc2l0aXZpdGllcyArIGZ1bGxfcm9jJHNwZWNpZmljaXRpZXMgLSAxKV0Kb3B0aW1hbF9jdXRvZmZfc3RlcHdpc2UgPC0gc3RlcHdpc2Vfcm9jJHNwZWNpZmljaXRpZXNbd2hpY2gubWF4KHN0ZXB3aXNlX3JvYyRzZW5zaXRpdml0aWVzICsgc3RlcHdpc2Vfcm9jJHNwZWNpZmljaXRpZXMgLSAxKV0Kb3B0aW1hbF9jdXRvZmZfYmljIDwtIGJpY19yb2Mkc3BlY2lmaWNpdGllc1t3aGljaC5tYXgoYmljX3JvYyRzZW5zaXRpdml0aWVzICsgYmljX3JvYyRzcGVjaWZpY2l0aWVzIC0gMSldCm9wdGltYWxfY3V0b2ZmX2xhc3NvIDwtIGxhc3NvX3JvYyRzcGVjaWZpY2l0aWVzW3doaWNoLm1heChsYXNzb19yb2Mkc2Vuc2l0aXZpdGllcyArIGxhc3NvX3JvYyRzcGVjaWZpY2l0aWVzIC0gMSldCgojIFByaW50IG9wdGltYWwgY3V0b2ZmcwpjYXQoIk9wdGltYWwgY3V0b2ZmIGZvciBGdWxsIE1vZGVsOiIsIG9wdGltYWxfY3V0b2ZmX2Z1bGwsICJcbiIpCmNhdCgiT3B0aW1hbCBjdXRvZmYgZm9yIFN0ZXB3aXNlIEFJQyBNb2RlbDoiLCBvcHRpbWFsX2N1dG9mZl9zdGVwd2lzZSwgIlxuIikKY2F0KCJPcHRpbWFsIGN1dG9mZiBmb3IgQklDIE1vZGVsOiIsIG9wdGltYWxfY3V0b2ZmX2JpYywgIlxuIikKY2F0KCJPcHRpbWFsIGN1dG9mZiBmb3IgTGFzc28gTW9kZWw6Iiwgb3B0aW1hbF9jdXRvZmZfbGFzc28sICJcbiIpCgojIFBsb3QgYWxsIFJPQyBjdXJ2ZXMKZ2dwbG90KCkgKwogIGdlb21fbGluZShhZXMoeCA9IGZ1bGxfcm9jJHNwZWNpZmljaXRpZXMsIHkgPSBmdWxsX3JvYyRzZW5zaXRpdml0aWVzLCBjb2xvciA9ICJGdWxsIE1vZGVsIikpICsKICBnZW9tX2xpbmUoYWVzKHggPSBzdGVwd2lzZV9yb2Mkc3BlY2lmaWNpdGllcywgeSA9IHN0ZXB3aXNlX3JvYyRzZW5zaXRpdml0aWVzLCBjb2xvciA9ICJTdGVwd2lzZSBBSUMiKSkgKwogIGdlb21fbGluZShhZXMoeCA9IGJpY19yb2Mkc3BlY2lmaWNpdGllcywgeSA9IGJpY19yb2Mkc2Vuc2l0aXZpdGllcywgY29sb3IgPSAiQklDIE1vZGVsIikpICsKICBnZW9tX2xpbmUoYWVzKHggPSBsYXNzb19yb2Mkc3BlY2lmaWNpdGllcywgeSA9IGxhc3NvX3JvYyRzZW5zaXRpdml0aWVzLCBjb2xvciA9ICJMYXNzbyBNb2RlbCIpKSArCiAgbGFicyh0aXRsZSA9ICJST0MgQ3VydmUgQ29tcGFyaXNvbiIsIHggPSAiMSAtIFNwZWNpZmljaXR5IiwgeSA9ICJTZW5zaXRpdml0eSIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygicmVkIiwgImJsdWUiLCAiZ3JlZW4iLCAicHVycGxlIiwgIm9yYW5nZSIpKSArCiAgdGhlbWVfbWluaW1hbCgpCgojIEFVQyB2YWx1ZXMKYXVjX3ZhbHVlcyA8LSBkYXRhLmZyYW1lKAogIE1vZGVsID0gYygiRnVsbCBNb2RlbCIsICJTdGVwd2lzZSBBSUMiLCAiQklDIE1vZGVsIiwgIkxhc3NvIE1vZGVsIiksCiAgQVVDID0gYyhhdWMoZnVsbF9yb2MpLCBhdWMoc3RlcHdpc2Vfcm9jKSwgYXVjKGJpY19yb2MpLCBhdWMobGFzc29fcm9jKSkKKQoKcHJpbnQoYXVjX3ZhbHVlcykKYGBgCgpBbGwgbW9kZWxzIGhhdmUgdmVyeSBzaW1pbGFyIEFVQy4gSW4gdHVybiwgdGhlIG1vcmUgcGFyc2ltb25pb3VzIG1vZGVsLCBCSUMsIGlzIHJlY29tbWVuZGVkLiAKCiMgQ09OQ0xVU0lPTgoKSW4gdGhpcyBhbmFseXNpcywgYSBjb21wcmVoZW5zaXZlIGFwcHJvYWNoIHdhcyB0YWtlbiB0byBleHBsb3JlIGFuZCBtb2RlbCB0aGUgTkhBTkVTIGRhdGFzZXQuIEJlZ2lubmluZyB3aXRoIEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMgKEVEQSksIHBhdHRlcm5zIGFuZCBtaXNzaW5nIHZhbHVlcyB3ZXJlIGlkZW50aWZpZWQsIGxlYWRpbmcgdG8gdGhlIGltcGxlbWVudGF0aW9uIG9mIE11bHRpcGxlIEltcHV0YXRpb24gYnkgQ2hhaW5lZCBFcXVhdGlvbnMgKE1JQ0UpIHRvIGhhbmRsZSBtaXNzaW5nIGRhdGEuIEZlYXR1cmUgZW5naW5lZXJpbmcgYW5kIHRyYW5zZm9ybWF0aW9uIHdlcmUgYXBwbGllZCB0byBlbmhhbmNlIG1vZGVsIHBlcmZvcm1hbmNlLCBmb2xsb3dlZCBieSBmZWF0dXJlIHNlbGVjdGlvbiB0byByZWZpbmUgcHJlZGljdG9yIHZhcmlhYmxlcy4gQm90aCBsaW5lYXIgYW5kIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWxzIHdlcmUgZGV2ZWxvcGVkIGFuZCBldmFsdWF0ZWQsIGluY2x1ZGluZyBmdWxsIG1vZGVscywgc3RlcHdpc2Ugc2VsZWN0aW9uIG1ldGhvZHMsIGFuZCByZWd1bGFyaXplZCByZWdyZXNzaW9uIHRlY2huaXF1ZXMuIFVsdGltYXRlbHksIHRoZSBCYXllc2lhbiBJbmZvcm1hdGlvbiBDcml0ZXJpb24gKEJJQykgZW1lcmdlZCBhcyB0aGUgYmVzdC1wZXJmb3JtaW5nIG1vZGVsIGZvciBib3RoIGxpbmVhciBhbmQgbG9naXN0aWMgcmVncmVzc2lvbiwgZGVtb25zdHJhdGluZyBpdHMgZWZmZWN0aXZlbmVzcyBpbiBiYWxhbmNpbmcgbW9kZWwgY29tcGxleGl0eSBhbmQgcHJlZGljdGl2ZSBhY2N1cmFjeS4K